updated elysia_cron, elfinder, metatag, libraries, email_registration, migrate, nodeform_cols

This commit is contained in:
2019-05-13 18:03:41 +02:00
parent e08a2639c6
commit 58cd990c8c
346 changed files with 8636 additions and 4770 deletions

View File

@@ -1,3 +1,29 @@
Next release
============
Features and enhancements
- #2552189 - Return migration status from drush migrate-import.
- #2550793 - Option to always use chunk IDs in MigrateContentParser.
- #2505683 - Pass item ID to MigrateContentParser implementations.
- #2532222 - Allow spreadsheet source data on a row different that 1.
- #1406802 - Add callback() field mapping method, to pass additional arguments
to callbacks.
- #2516828 - Add mdreg alias for migrate-deregister.
- #2504517 - Add timezone handling to timestamp().
Bug fixes
- #2612110 - Notice when units omitted on --limit.
- #2597606 - Escape MySQL database names.
- #2577091 - Do strict type-check on XML ids.
- #2537206 - copy() return not checked.
- #2536616 - Improve message when sourceMigration not found.
- #2578391 - Improve message when class not found.
- #2565043 - Handle empty idlist in MigrateSourceMultiItems.
- #2510010 - Stop stripping group name prefixes from migration names.
- #2542520 - Fallback for missing source key description.
- #2499861 - Properly save/disable/restore mail system.
- #2541996 - Prevent NULL file_mask being passed to file_scan_directory().
Migrate 2.8
===========

View File

@@ -1,15 +1,17 @@
The Migrate module provides a flexible framework for migrating content into Drupal
from other sources (e.g., when converting a web site from another CMS to Drupal).
The Migrate module provides a flexible framework for migrating content into
Drupal from other sources
(e.g., when converting a web site from another CMS to Drupal).
Out-of-the-box, support for creating Drupal nodes, taxonomy terms, comments, and
users are included. Plugins permit migration of other types of content.
Usage
-----
Documentation is at http://drupal.org/migrate. To get started, enable the
migrate_example module and browse to admin/content/migrate to see its dashboard.
The code for this migration is in migrate_example/beer.inc (advanced examples are
in wine.inc). Mimic that file in order to specify your own migrations.
migrate_example module, enable migrate_ui, and then browse to
admin/content/migrate to see its dashboard.
The code for this migration is in migrate_example/beer.inc
(advanced examples are in wine.inc). Mimic that file in order to specify your
own migrations.
The Migrate module itself has support for migration into core objects. Support
for migration involving contrib modules is in the migrate_extras module.
@@ -17,8 +19,8 @@ for migration involving contrib modules is in the migrate_extras module.
Known issues
------------
A user migration with systemOfRecord == DESTINATION will drop pictures from user
records due to core bug http://drupal.org/node/935592 - the simpletests report an
error reflecting this. We have not developed a work-around.
records due to core bug http://drupal.org/node/935592 - the simpletests report
an error reflecting this. We have not developed a work-around.
Upgrading
---------
@@ -30,9 +32,9 @@ projects.
Acknowledgements
----------------
Much of the Migrate module functionality was sponsored by Cyrve, for its clients GenomeWeb
(http://www.genomeweb.com), The Economist (http://www.economist.com), and Examiner.com
(http://www.examiner.com).
Much of the Migrate module functionality was sponsored by Cyrve, for its clients
GenomeWeb (http://www.genomeweb.com), The Economist (http://www.economist.com),
and Examiner.com (http://www.examiner.com).
Authors
-------

View File

@@ -8,11 +8,12 @@
/**
* The base class for all objects representing distinct steps in a migration
* process. Most commonly these will be Migration objects which actually import
* data from a source into a Drupal destination, but by deriving classes directly
* from MigrationBase one can have other sorts of tasks (e.g., enabling/disabling
* of modules) occur during the migration process.
* data from a source into a Drupal destination, but by deriving classes
* directly from MigrationBase one can have other sorts of tasks (e.g.,
* enabling/disabling of modules) occur during the migration process.
*/
abstract class MigrationBase {
/**
* Track the migration currently running, so handlers can easily determine it
* without having to pass a Migration object everywhere.
@@ -20,18 +21,21 @@ abstract class MigrationBase {
* @var Migration
*/
protected static $currentMigration;
public static function currentMigration() {
return self::$currentMigration;
}
/**
* The machine name of this Migration object, derived by removing the 'Migration'
* suffix from the class name. Used to construct default map/message table names,
* displayed in drush migrate-status, key to migrate_status table...
* The machine name of this Migration object, derived by removing the
* 'Migration' suffix from the class name. Used to construct default
* map/message table names, displayed in drush migrate-status, key to
* migrate_status table...
*
* @var string
*/
protected $machineName;
public function getMachineName() {
return $this->machineName;
}
@@ -42,6 +46,7 @@ abstract class MigrationBase {
* @var MigrateGroup
*/
protected $group;
public function getGroup() {
return $this->group;
}
@@ -52,18 +57,22 @@ abstract class MigrationBase {
* @var string
*/
protected $description;
public function getDescription() {
return $this->description;
}
public function setDescription($description) {
$this->description = $description;
}
/**
* Save options passed to current operation
*
* @var array
*/
protected $options;
public function getOption($option_name) {
if (isset($this->options[$option_name])) {
return $this->options[$option_name];
@@ -72,18 +81,20 @@ abstract class MigrationBase {
return NULL;
}
}
public function getItemLimit() {
if (isset($this->options['limit']) &&
($this->options['limit']['unit'] == 'items' || $this->options['limit']['unit'] == 'item')) {
($this->options['limit']['unit'] == 'items' || $this->options['limit']['unit'] == 'item')) {
return $this->options['limit']['value'];
}
else {
return NULL;
}
}
public function getTimeLimit() {
if (isset($this->options['limit']) &&
($this->options['limit']['unit'] == 'seconds' || $this->options['limit']['unit'] == 'second')) {
($this->options['limit']['unit'] == 'seconds' || $this->options['limit']['unit'] == 'second')) {
return $this->options['limit']['value'];
}
else {
@@ -108,6 +119,7 @@ abstract class MigrationBase {
/**
* When the current operation started.
*
* @var int
*/
protected $starttime;
@@ -137,41 +149,51 @@ abstract class MigrationBase {
/**
* List of other Migration classes which should be imported before this one.
* E.g., a comment migration class would typically have node and user migrations
* as dependencies.
* E.g., a comment migration class would typically have node and user
* migrations as dependencies.
*
* @var array
*/
protected $dependencies = array(), $softDependencies = array();
public function getHardDependencies() {
return $this->dependencies;
}
public function setHardDependencies(array $dependencies) {
$this->dependencies = $dependencies;
}
public function addHardDependencies(array $dependencies) {
$this->dependencies = array_merge($this->dependencies, $dependencies);
}
public function getSoftDependencies() {
return $this->softDependencies;
}
public function setSoftDependencies(array $dependencies) {
$this->softDependencies = $dependencies;
}
public function addSoftDependencies(array $dependencies) {
$this->softDependencies = array_merge($this->softDependencies, $dependencies);
}
public function getDependencies() {
return array_merge($this->dependencies, $this->softDependencies);
}
/**
* Name of a function for displaying feedback. It must take the message to display
* as its first argument, and a (string) message type as its second argument
* Name of a function for displaying feedback. It must take the message to
* display as its first argument, and a (string) message type as its second
* argument
* (see drush_log()).
*
* @var string
*/
protected static $displayFunction;
public static function setDisplayFunction($display_function) {
self::$displayFunction = $display_function;
}
@@ -230,9 +252,11 @@ abstract class MigrationBase {
* @var array
*/
protected $team = array();
public function getTeam() {
return $this->team;
}
public function setTeam(array $team) {
$this->team = $team;
}
@@ -244,9 +268,11 @@ abstract class MigrationBase {
* @var string
*/
protected $issuePattern;
public function getIssuePattern() {
return $this->issuePattern;
}
public function setIssuePattern($issue_pattern) {
$this->issuePattern = $issue_pattern;
}
@@ -265,12 +291,15 @@ abstract class MigrationBase {
* @var array
*/
protected $arguments = array();
public function getArguments() {
return $this->arguments;
}
public function setArguments(array $arguments) {
$this->arguments = $arguments;
}
public function addArguments(array $arguments) {
$this->arguments = array_merge($this->arguments, $arguments);
}
@@ -282,9 +311,11 @@ abstract class MigrationBase {
* @var boolean
*/
protected $enabled = TRUE;
public function getEnabled() {
return $this->enabled;
}
public function setEnabled($enabled) {
$this->enabled = $enabled;
}
@@ -294,9 +325,11 @@ abstract class MigrationBase {
*
* @var array
* Key: Hook name (e.g., 'node_insert')
* Value: Array of modules for which to disable this hook (e.g., array('pathauto')).
* Value: Array of modules for which to disable this hook (e.g.,
* array('pathauto')).
*/
protected $disableHooks = array();
public function getDisableHooks() {
return $this->disableHooks;
}
@@ -304,26 +337,33 @@ abstract class MigrationBase {
/**
* An array to track 'mail_system' variable if disabled.
*/
protected $mailSystem = array();
protected $mailSystem;
/**
* Have we already warned about obsolete constructor argumentss on this request?
* Have we already warned about obsolete constructor argumentss on this
* request?
*
* @var bool
*/
static protected $groupArgumentWarning = FALSE;
static protected $emptyArgumentsWarning = FALSE;
/**
* Codes representing the result of a rollback or import process.
*/
const RESULT_COMPLETED = 1; // All records have been processed
const RESULT_INCOMPLETE = 2; // The process has interrupted itself (e.g., the
// memory limit is approaching)
// memory limit is approaching)
const RESULT_STOPPED = 3; // The process was stopped externally (e.g., via
// drush migrate-stop)
// drush migrate-stop)
const RESULT_FAILED = 4; // The process had a fatal error
const RESULT_SKIPPED = 5; // Dependencies are unfulfilled - skip the process
const RESULT_DISABLED = 6; // This migration is disabled, skipping
/**
@@ -331,20 +371,27 @@ abstract class MigrationBase {
* migrate_status table.
*/
const STATUS_IDLE = 0;
const STATUS_IMPORTING = 1;
const STATUS_ROLLING_BACK = 2;
const STATUS_STOPPING = 3;
const STATUS_DISABLED = 4;
/**
* Message types to be passed to saveMessage() and saved in message tables.
* MESSAGE_INFORMATIONAL represents a condition that did not prevent the operation
* from succeeding - all others represent different severities of conditions
* resulting in a source record not being imported.
* MESSAGE_INFORMATIONAL represents a condition that did not prevent the
* operation from succeeding - all others represent different severities of
* conditions resulting in a source record not being imported.
*/
const MESSAGE_ERROR = 1;
const MESSAGE_WARNING = 2;
const MESSAGE_NOTICE = 3;
const MESSAGE_INFORMATIONAL = 4;
/**
@@ -374,7 +421,7 @@ abstract class MigrationBase {
$this->group = $arguments;
$this->arguments['group_name'] = $arguments->getName();
if (!self::$groupArgumentWarning &&
variable_get('migrate_deprecation_warnings', 1)) {
variable_get('migrate_deprecation_warnings', 1)) {
self::displayMessage(t('Passing a group object to a migration constructor is now deprecated - pass through the arguments array passed to the leaf class instead.'));
self::$groupArgumentWarning = TRUE;
}
@@ -383,7 +430,7 @@ abstract class MigrationBase {
if (empty($arguments)) {
$this->arguments = array();
if (!self::$emptyArgumentsWarning &&
variable_get('migrate_deprecation_warnings', 1)) {
variable_get('migrate_deprecation_warnings', 1)) {
self::displayMessage(t('Passing an empty first parameter to a migration constructor is now deprecated - pass through the arguments array passed to the leaf class instead.'));
self::$emptyArgumentsWarning = TRUE;
}
@@ -417,7 +464,8 @@ abstract class MigrationBase {
}
else {
if (!is_numeric($limit)) {
$last = drupal_strtolower($limit[strlen($limit)-1]);
$last = drupal_strtolower($limit[strlen($limit) - 1]);
$limit = substr($limit, 0, -1);
switch ($last) {
case 'g':
$limit *= 1024;
@@ -437,18 +485,12 @@ abstract class MigrationBase {
// Record the time limit
$this->timeLimit = ini_get('max_execution_time');
// Save the current mail system, prior to disabling emails.
$this->saveMailSystem();
// Prevent emails from being sent out during migrations.
$this->disableMailSystem();
// Make sure we clear our semaphores in case of abrupt exit
drupal_register_shutdown_function(array($this, 'endProcess'));
// Save any hook disablement information.
if (isset($this->arguments['disable_hooks']) &&
is_array($this->arguments['disable_hooks'])) {
is_array($this->arguments['disable_hooks'])) {
$this->disableHooks = $this->arguments['disable_hooks'];
}
}
@@ -477,7 +519,7 @@ abstract class MigrationBase {
* @param array $arguments
*/
static public function registerMigration($class_name, $machine_name = NULL,
array $arguments = array()) {
array $arguments = array()) {
// Support for legacy migration code - in later releases, the machine_name
// should always be explicit.
if (!$machine_name) {
@@ -486,7 +528,7 @@ abstract class MigrationBase {
if (!preg_match('|^[a-z0-9_]+$|i', $machine_name)) {
throw new Exception(t('!name is not a valid Migration machine name. Use only alphanumeric or underscore characters.',
array('!name' => $machine_name)));
array('!name' => $machine_name)));
}
// We no longer have any need to store the machine_name in the arguments.
@@ -509,10 +551,10 @@ abstract class MigrationBase {
db_merge('migrate_status')
->key(array('machine_name' => $machine_name))
->fields(array(
'class_name' => $class_name,
'group_name' => $group_name,
'arguments' => serialize($arguments)
))
'class_name' => $class_name,
'group_name' => $group_name,
'arguments' => serialize($arguments),
))
->execute();
}
@@ -524,8 +566,8 @@ abstract class MigrationBase {
*/
static public function deregisterMigration($machine_name) {
$rows_deleted = db_delete('migrate_status')
->condition('machine_name', $machine_name)
->execute();
->condition('machine_name', $machine_name)
->execute();
// Make sure the group gets deleted if we were the only member.
MigrateGroup::deleteOrphans();
}
@@ -583,10 +625,10 @@ abstract class MigrationBase {
if (!isset($migrations[$machine_name_key])) {
// See if we know about this migration
$row = db_select('migrate_status', 'ms')
->fields('ms', array('class_name', 'group_name', 'arguments'))
->condition('machine_name', $machine_name)
->execute()
->fetchObject();
->fields('ms', array('class_name', 'group_name', 'arguments'))
->condition('machine_name', $machine_name)
->execute()
->fetchObject();
if ($row) {
$class_name = $row->class_name;
$arguments = unserialize($row->arguments);
@@ -603,8 +645,7 @@ abstract class MigrationBase {
if (class_exists($class_name)) {
try {
$migrations[$machine_name_key] = new $class_name($arguments);
}
catch (Exception $e) {
} catch (Exception $e) {
self::displayMessage(t('Migration !machine could not be constructed.',
array('!machine' => $machine_name)));
self::displayMessage($e->getMessage());
@@ -665,12 +706,14 @@ abstract class MigrationBase {
}
/**
* Output the given message appropriately (drush_print/drupal_set_message/etc.)
* Output the given message appropriately
* (drush_print/drupal_set_message/etc.)
*
* @param string $message
* The message to output.
* @param int $level
* Optional message severity as understood by drupal_set_message and drush_log
* Optional message severity as understood by drupal_set_message and
* drush_log
* (defaults to 'error').
*/
static public function displayMessage($message, $level = 'error') {
@@ -690,12 +733,13 @@ abstract class MigrationBase {
* @param $line
* The line number the error was raised at.
* @param $context
* An array that points to the active symbol table at the point the error occurred.
* An array that points to the active symbol table at the point the error
* occurred.
*/
public function errorHandler($error_level, $message, $filename, $line, $context) {
if ($error_level & error_reporting()) {
$message .= "\n" . t('File !file, line !line',
array('!line' => $line, '!file' => $filename));
array('!line' => $line, '!file' => $filename));
// Record notices and continue
if ($error_level == E_NOTICE || $error_level == E_USER_NOTICE) {
$this->saveMessage($message . "(file: $filename, line $line)", MigrationBase::MESSAGE_INFORMATIONAL);
@@ -703,20 +747,21 @@ abstract class MigrationBase {
// Simply ignore strict and deprecated errors
// Note DEPRECATED constants introduced in PHP 5.3
elseif (!($error_level == E_STRICT || $error_level == 8192 ||
$error_level == 16384)) {
$error_level == 16384)) {
throw new MigrateException($message, MigrationBase::MESSAGE_ERROR);
}
}
}
/**
* Takes an Exception object and both saves and displays it, pulling additional
* information on the location triggering the exception.
* Takes an Exception object and both saves and displays it, pulling
* additional information on the location triggering the exception.
*
* @param Exception $exception
* Object representing the exception.
* @param boolean $save
* Whether to save the message in the migration's mapping table. Set to FALSE
* Whether to save the message in the migration's mapping table. Set to
* FALSE
* in contexts where this doesn't make sense.
*/
public function handleException($exception, $save = TRUE) {
@@ -730,6 +775,7 @@ abstract class MigrationBase {
/**
* Check the current status of a migration.
*
* @return int
* One of the MigrationBase::STATUS_* constants
*/
@@ -738,10 +784,10 @@ abstract class MigrationBase {
return MigrationBase::STATUS_DISABLED;
}
$status = db_select('migrate_status', 'ms')
->fields('ms', array('status'))
->condition('machine_name', $this->machineName)
->execute()
->fetchField();
->fields('ms', array('status'))
->condition('machine_name', $this->machineName)
->execute()
->fetchField();
if (!isset($status)) {
$status = MigrationBase::STATUS_IDLE;
}
@@ -750,19 +796,20 @@ abstract class MigrationBase {
/**
* Retrieve the last time an import operation completed successfully.
*
* @return string
* Date/time string, formatted... How? Default DB server format?
*/
public function getLastImported() {
$last_imported = db_select('migrate_log', 'ml')
->fields('ml', array('endtime'))
->condition('machine_name', $this->machineName)
->isNotNull('endtime')
->orderBy('endtime', 'DESC')
->execute()
->fetchField();
->fields('ml', array('endtime'))
->condition('machine_name', $this->machineName)
->isNotNull('endtime')
->orderBy('endtime', 'DESC')
->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', $last_imported / 1000);
}
else {
$last_imported = '';
@@ -778,10 +825,10 @@ abstract class MigrationBase {
*/
public function getHighwater() {
$highwater = db_select('migrate_status', 'ms')
->fields('ms', array('highwater'))
->condition('machine_name', $this->machineName)
->execute()
->fetchField();
->fields('ms', array('highwater'))
->condition('machine_name', $this->machineName)
->execute()
->fetchField();
return $highwater;
}
@@ -796,8 +843,8 @@ abstract class MigrationBase {
protected function saveHighwater($highwater, $force = FALSE) {
if (!isset($this->options['idlist'])) {
$query = db_update('migrate_status')
->fields(array('highwater' => $highwater))
->condition('machine_name', $this->machineName);
->fields(array('highwater' => $highwater))
->condition('machine_name', $this->machineName);
if (!$force) {
if (!empty($this->highwaterField['type']) && $this->highwaterField['type'] == 'int') {
// If the highwater is an integer type, we need to force the DB server
@@ -808,9 +855,8 @@ abstract class MigrationBase {
$query->where('(CASE WHEN highwater=\'\' THEN 0 ELSE CAST(highwater AS INTEGER) END) < :highwater', array(':highwater' => intval($highwater)));
break;
default:
// CAST(highwater AS INTEGER) would be ideal, but won't
// work in MySQL. This hack is thought to be portable.
$query->where('(highwater+0) < :highwater', array(':highwater' => $highwater));
// MySQL casts as integers as SIGNED or UNSIGNED.
$query->where('(CASE WHEN highwater=\'\' THEN 0 ELSE CAST(highwater AS SIGNED) END) < :highwater', array(':highwater' => intval($highwater)));
}
}
else {
@@ -823,20 +869,21 @@ abstract class MigrationBase {
/**
* Retrieve the last throughput for current Migration (items / minute).
*
* @return integer
*/
public function getLastThroughput() {
$last_throughput = 0;
$row = db_select('migrate_log', 'ml')
->fields('ml', array('starttime', 'endtime', 'numprocessed'))
->condition('machine_name', $this->machineName)
->condition('process_type', 1)
->isNotNull('endtime')
->orderBy('starttime', 'DESC')
->execute()
->fetchObject();
->fields('ml', array('starttime', 'endtime', 'numprocessed'))
->condition('machine_name', $this->machineName)
->condition('process_type', 1)
->isNotNull('endtime')
->orderBy('starttime', 'DESC')
->execute()
->fetchObject();
if ($row) {
$elapsed = ($row->endtime - $row->starttime)/1000;
$elapsed = ($row->endtime - $row->starttime) / 1000;
if ($elapsed > 0) {
$last_throughput = round(($row->numprocessed / $elapsed) * 60);
}
@@ -846,8 +893,9 @@ abstract class MigrationBase {
/**
* Reports whether this migration process is complete. For a Migration, for
* example, this would be whether all available source rows have been processed.
* Other MigrationBase classes will need to return TRUE/FALSE appropriately.
* example, this would be whether all available source rows have been
* processed. Other MigrationBase classes will need to return TRUE/FALSE
* appropriately.
*/
abstract public function isComplete();
@@ -904,6 +952,12 @@ abstract class MigrationBase {
// Try to make the semaphore handling atomic (depends on DB support)
$transaction = db_transaction();
// Save the current mail system, prior to disabling emails.
$this->saveMailSystem();
// Prevent emails from being sent out during migrations.
$this->disableMailSystem();
$this->starttime = microtime(TRUE);
// Check to make sure there's no process already running for this migration
@@ -922,19 +976,22 @@ abstract class MigrationBase {
// Set an error handler for imports
if ($newStatus == MigrationBase::STATUS_IMPORTING) {
$this->previousErrorHandler = set_error_handler(array($this, 'errorHandler'));
$this->previousErrorHandler = set_error_handler(array(
$this,
'errorHandler',
));
}
// Save the initial history record
if ($this->logHistory) {
$this->logID = db_insert('migrate_log')
->fields(array(
'machine_name' => $this->machineName,
'process_type' => $newStatus,
'starttime' => round(microtime(TRUE) * 1000),
'initialHighwater' => $this->getHighwater(),
))
->execute();
->fields(array(
'machine_name' => $this->machineName,
'process_type' => $newStatus,
'starttime' => round(microtime(TRUE) * 1000),
'initialHighwater' => $this->getHighwater(),
))
->execute();
}
// If we're disabling any hooks, reset the static module_implements cache so
@@ -950,8 +1007,8 @@ abstract class MigrationBase {
}
/**
* End a rollback or import process, releasing the semaphore. Note that it must
* be public to be callable as the shutdown function.
* End a rollback or import process, releasing the semaphore. Note that it
* must be public to be callable as the shutdown function.
*/
public function endProcess() {
if ($this->previousErrorHandler) {
@@ -960,7 +1017,14 @@ abstract class MigrationBase {
}
if ($this->processing) {
$this->status = MigrationBase::STATUS_IDLE;
$fields = array('class_name' => get_class($this), 'status' => MigrationBase::STATUS_IDLE);
// Restore the previous mail handler.
$this->restoreMailSystem();
$fields = array(
'class_name' => get_class($this),
'status' => MigrationBase::STATUS_IDLE,
);
db_merge('migrate_status')
->key(array('machine_name' => $this->machineName))
->fields($fields)
@@ -977,10 +1041,9 @@ abstract class MigrationBase {
'numprocessed' => $this->total_processed,
))
->execute();
}
catch (PDOException $e) {
} catch (PDOException $e) {
Migration::displayMessage(t('Could not log operation on migration !name - possibly MigrationBase::beginProcess() was not called',
array('!name' => $this->machineName)));
array('!name' => $this->machineName)));
}
}
@@ -1035,8 +1098,7 @@ abstract class MigrationBase {
$this->beginProcess(MigrationBase::STATUS_ROLLING_BACK);
try {
$return = $this->rollback();
}
catch (Exception $exception) {
} catch (Exception $exception) {
// If something bad happened, make sure we clear the semaphore
$this->endProcess();
throw $exception;
@@ -1071,8 +1133,7 @@ abstract class MigrationBase {
$this->beginProcess(MigrationBase::STATUS_IMPORTING);
try {
$return = $this->import();
}
catch (Exception $exception) {
} catch (Exception $exception) {
// If something bad happened, make sure we clear the semaphore
$this->endProcess();
throw $exception;
@@ -1117,43 +1178,50 @@ abstract class MigrationBase {
*/
/**
* Test whether we've exceeded the desired memory threshold. If so, output a message.
* Test whether we've exceeded the desired memory threshold. If so, output a
* message.
*
* @return boolean
* TRUE if the threshold is exceeded, FALSE if not.
*/
protected function memoryExceeded() {
$usage = memory_get_usage();
$pct_memory = $usage/$this->memoryLimit;
$pct_memory = $usage / $this->memoryLimit;
if ($pct_memory > $this->memoryThreshold) {
self::displayMessage(
t('Memory usage is !usage (!pct% of limit !limit), resetting statics',
array('!pct' => round($pct_memory*100),
'!usage' => format_size($usage),
'!limit' => format_size($this->memoryLimit))),
array(
'!pct' => round($pct_memory * 100),
'!usage' => format_size($usage),
'!limit' => format_size($this->memoryLimit),
)),
'warning');
// First, try resetting Drupal's static storage - this frequently releases
// plenty of memory to continue
drupal_static_reset();
$usage = memory_get_usage();
$pct_memory = $usage/$this->memoryLimit;
$pct_memory = $usage / $this->memoryLimit;
// Use a lower threshold - we don't want to be in a situation where we keep
// coming back here and trimming a tiny amount
if ($pct_memory > (.90 * $this->memoryThreshold)) {
self::displayMessage(
t('Memory usage is now !usage (!pct% of limit !limit), not enough reclaimed, starting new batch',
array('!pct' => round($pct_memory*100),
'!usage' => format_size($usage),
'!limit' => format_size($this->memoryLimit))),
array(
'!pct' => round($pct_memory * 100),
'!usage' => format_size($usage),
'!limit' => format_size($this->memoryLimit),
)),
'warning');
return TRUE;
}
else {
self::displayMessage(
t('Memory usage is now !usage (!pct% of limit !limit), reclaimed enough, continuing',
array('!pct' => round($pct_memory*100),
'!usage' => format_size($usage),
'!limit' => format_size($this->memoryLimit))),
array(
'!pct' => round($pct_memory * 100),
'!usage' => format_size($usage),
'!limit' => format_size($this->memoryLimit),
)),
'warning');
return FALSE;
}
@@ -1204,37 +1272,23 @@ abstract class MigrationBase {
/**
* Encrypt an incoming value. Detects for existence of the Drupal 'Encrypt'
* module or the mcrypt PHP extension.
* module.
*
* @param string $value
*
* @return string The encrypted value.
*/
static public function encrypt($value) {
if (module_exists('encrypt')) {
$value = encrypt($value);
}
else if (extension_loaded('mcrypt')) {
// Mimic encrypt module to ensure compatibility
$key = drupal_substr(variable_get('drupal_private_key', 'no_key'), 0, 32);
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$value = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $value,
MCRYPT_MODE_ECB, $iv);
$encryption_array['text'] = $value;
// For forward compatibility with the encrypt module.
$encryption_array['method'] = 'mcrypt_rij_256';
$encryption_array['key_name'] = 'drupal_private_key';
$value = serialize($encryption_array);
}
else {
if (self::$showEncryptionWarning) {
MigrationBase::displayMessage(t('Encryption of secure migration information is not supported. Ensure the <a href="@encrypt">Encrypt module</a> or <a href="mcrypt">mcrypt PHP extension</a> is installed for this functionality.',
array(
'@encrypt' => 'http://drupal.org/project/encrypt',
'@mcrypt' => 'http://php.net/manual/en/book.mcrypt.php',
)
),
MigrationBase::displayMessage(t('Encryption of secure migration information is not supported. Ensure the <a href="@encrypt">Encrypt module</a> is installed for this functionality.',
array(
'@encrypt' => 'http://drupal.org/project/encrypt',
)
),
'warning');
self::$showEncryptionWarning = FALSE;
}
@@ -1246,33 +1300,20 @@ abstract class MigrationBase {
* Decrypt an incoming value.
*
* @param string $value
*
* @return string The encrypted value
*/
static public function decrypt($value) {
if (module_exists('encrypt')) {
$value = decrypt($value);
}
else if (extension_loaded('mcrypt')) {
// Mimic encrypt module to ensure compatibility
$encryption_array = unserialize($value);
$method = $encryption_array['method']; // Not used right now
$text = $encryption_array['text'];
$key_name = $encryption_array['key_name']; // Not used right now
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$key = drupal_substr(variable_get('drupal_private_key', 'no_key'), 0, 32);
$value = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $text,
MCRYPT_MODE_ECB, $iv);
}
else {
if (self::$showEncryptionWarning) {
MigrationBase::displayMessage(t('Encryption of secure migration information is not supported. Ensure the <a href="@encrypt">Encrypt module</a> or <a href="mcrypt">mcrypt PHP extension</a> is installed for this functionality.',
array(
'@encrypt' => 'http://drupal.org/project/encrypt',
'@mcrypt' => 'http://php.net/manual/en/book.mcrypt.php',
)
),
MigrationBase::displayMessage(t('Encryption of secure migration information is not supported. Ensure the <a href="@encrypt">Encrypt module</a> is installed for this functionality.',
array(
'@encrypt' => 'http://drupal.org/project/encrypt',
)
),
'warning');
self::$showEncryptionWarning = FALSE;
}
@@ -1329,12 +1370,18 @@ abstract class MigrationBase {
}
/**
* Convert an incoming string (which may be a UNIX timestamp, or an arbitrarily-formatted
* date/time string) to a UNIX timestamp.
* Convert an incoming string (which may be a UNIX timestamp, or an
* arbitrarily-formatted date/time string) to a UNIX timestamp.
*
* @param string $value
* The time string to convert.
* @param string $timezone
* Optional timezone for the time string. NULL to leave the timezone unset.
*
* @return string
* The UNIX timestamp.
*/
static public function timestamp($value) {
static public function timestamp($value, $timezone = NULL) {
// Does it look like it's already a timestamp? Just return it
if (is_numeric($value)) {
return $value;
@@ -1345,7 +1392,10 @@ abstract class MigrationBase {
return time();
}
$date = new DateTime($value);
if (isset($timezone)) {
$timezone = new DateTimeZone($timezone);
}
$date = new DateTime($value, $timezone);
$time = $date->format('U');
if ($time == FALSE) {
// Handles form YYYY-MM-DD HH:MM:SS.garbage
@@ -1359,14 +1409,9 @@ abstract class MigrationBase {
/**
* Saves the current mail system, or set a system default if there is none.
*/
protected function saveMailSystem() {
public function saveMailSystem() {
global $conf;
if (empty($conf['mail_system'])) {
$conf['mail_system']['default-system'] = 'MigrateMailIgnore';
}
else {
$this->mailSystem = $conf['mail_system'];
}
$this->mailSystem = empty($conf['mail_system']) ? NULL : $conf['mail_system'];
}
/**
@@ -1379,6 +1424,9 @@ abstract class MigrationBase {
$conf['mail_system'][$system] = 'MigrateMailIgnore';
}
}
else {
$conf['mail_system'] = array('default-system' => 'MigrateMailIgnore');
}
}
/**

View File

@@ -13,11 +13,12 @@
* MigrateDestinationEntity for an example.
*/
abstract class MigrateDestination {
/**
* To support MigrateSQLMap maps, derived destination classes should return
* schema field definition(s) corresponding to the primary key of the destination
* being implemented. These are used to construct the destination key fields
* of the map table for a migration using this destination.
* schema field definition(s) corresponding to the primary key of the
* destination being implemented. These are used to construct the destination
* key fields of the map table for a migration using this destination.
*
* abstract static public function getKeySchema()
*/
@@ -36,6 +37,7 @@ abstract class MigrateDestination {
*
* @param Migration $migration
* Optionally, the migration containing this destination.
*
* @return array
* Keys: machine names of the fields (to be passed to addFieldMapping)
* Values: Human-friendly descriptions of the fields.
@@ -43,9 +45,9 @@ abstract class MigrateDestination {
abstract public function fields();
/**
* Derived classes must implement either bulkRollback or rollback() according to
* the signatures below, to rollback (usually by deletion) previously-migrated
* items.
* Derived classes must implement either bulkRollback or rollback() according
* to the signatures below, to rollback (usually by deletion)
* previously-migrated items.
*
* $ids is an array of single-field keys to be deleted
* abstract public function bulkRollback(array $ids);
@@ -55,9 +57,10 @@ abstract class MigrateDestination {
*/
/**
* Derived classes must implement import(), to construct one new object (pre-pppulated
* using field mappings in the Migration). It is expected to call prepare and
* complete handlers, passing them $row (the raw data from the source).
* Derived classes must implement import(), to construct one new object
* (pre-pppulated using field mappings in the Migration). It is expected to
* call prepare and complete handlers, passing them $row (the raw data from
* the source).
*/
abstract public function import(stdClass $object, stdClass $row);
@@ -78,10 +81,13 @@ abstract class MigrateDestination {
* @var int
*/
protected $numCreated = 0;
public function getCreated() {
return $this->numCreated;
}
protected $numUpdated = 0;
public function getUpdated() {
return $this->numUpdated;
}
@@ -105,6 +111,7 @@ abstract class MigrateDestination {
* All destination handlers should be derived from MigrateDestinationHandler
*/
abstract class MigrateDestinationHandler extends MigrateHandler {
// Any one or more of these methods may be implemented
/**
@@ -116,6 +123,7 @@ abstract class MigrateDestinationHandler extends MigrateHandler {
* The bundle (article, blog, etc.), if any, for which to list fields.
* @param Migration $migration
* Optionally, the migration providing the context.
*
* @return array
* An array keyed by field name, with field descriptions as values.
*/

View File

@@ -6,11 +6,14 @@
*/
class MigrateException extends Exception {
/**
* The level of the error being reported (a Migration::MESSAGE_* constant)
*
* @var int
*/
protected $level;
public function getLevel() {
return $this->level;
}
@@ -22,6 +25,7 @@ class MigrateException extends Exception {
* @var int
*/
protected $status;
public function getStatus() {
return $this->status;
}

View File

@@ -7,6 +7,7 @@
*/
class MigrateFieldMapping {
/**
* Destination field name for the mapping. If empty, the mapping is just a
* stub for annotating the source field.
@@ -14,6 +15,7 @@ class MigrateFieldMapping {
* @var string
*/
protected $destinationField;
public function getDestinationField() {
return $this->destinationField;
}
@@ -25,6 +27,7 @@ class MigrateFieldMapping {
* @var string
*/
protected $sourceField;
public function getSourceField() {
return $this->sourceField;
}
@@ -33,11 +36,15 @@ class MigrateFieldMapping {
* @var int
*/
const MAPPING_SOURCE_CODE = 1;
const MAPPING_SOURCE_DB = 2;
protected $mappingSource = self::MAPPING_SOURCE_CODE;
public function getMappingSource() {
return $this->mappingSource;
}
public function setMappingSource($mapping_source) {
$this->mappingSource = $mapping_source;
}
@@ -50,6 +57,7 @@ class MigrateFieldMapping {
* @var mixed
*/
protected $defaultValue;
public function getDefaultValue() {
return $this->defaultValue;
}
@@ -61,6 +69,7 @@ class MigrateFieldMapping {
* @var string
*/
protected $separator;
public function getSeparator() {
return $this->separator;
}
@@ -74,6 +83,7 @@ class MigrateFieldMapping {
* An array of source migrations, or string for a single migration.
*/
protected $sourceMigration;
public function getSourceMigration() {
return $this->sourceMigration;
}
@@ -84,6 +94,7 @@ class MigrateFieldMapping {
* @var string
*/
protected $callbacks = array();
public function getCallbacks() {
return $this->callbacks;
}
@@ -99,6 +110,7 @@ class MigrateFieldMapping {
* @var string
*/
protected $dedupe;
public function getDedupe() {
return $this->dedupe;
}
@@ -106,41 +118,49 @@ class MigrateFieldMapping {
/**
* Argument overrides. If present this will be an array, keyed by
* a field API array key, with one or both of these entries:
* 'source_field' - Name of the source field in the incoming row containing the
* value to be assigned
* 'default_value' - A constant value to be assigned in the absence of source_field
* Deprecated - subfield notation is now preferred.
* 'source_field' - Name of the source field in the incoming row containing
* the value to be assigned
* 'default_value' - A constant value to be assigned in the absence of
* source_field Deprecated - subfield notation is now preferred.
*
* @var array
*/
protected $arguments;
public function getArguments() {
return $this->arguments;
}
protected $description = '';
public function getDescription() {
return $this->description;
}
protected $issueGroup;
public function getIssueGroup() {
return $this->issueGroup;
}
protected $issueNumber;
public function getIssueNumber() {
return $this->issueNumber;
}
protected $issuePriority = self::ISSUE_PRIORITY_OK;
public function getIssuePriority() {
return $this->issuePriority;
}
const ISSUE_PRIORITY_OK = 1;
const ISSUE_PRIORITY_LOW = 2;
const ISSUE_PRIORITY_MEDIUM = 3;
const ISSUE_PRIORITY_BLOCKER = 4;
public static $priorities = array();
@@ -177,7 +197,17 @@ class MigrateFieldMapping {
}
public function callbacks($callbacks) {
$this->callbacks = func_get_args();
foreach (func_get_args() as $callback) {
$this->callback($callback);
}
return $this;
}
public function callback($callback) {
$this->callbacks[] = array(
'callback' => $callback,
'params' => array_slice(func_get_args(), 1),
);
return $this;
}

View File

@@ -6,12 +6,14 @@
*/
class MigrateGroup {
/**
* The machine name of the group - used to identify it in drush commands.
*
* @var string
*/
protected $name;
public function getName() {
return $this->name;
}
@@ -22,6 +24,7 @@ class MigrateGroup {
* @var string
*/
protected $title;
public function getTitle() {
return $this->title;
}
@@ -33,6 +36,7 @@ class MigrateGroup {
* @var array
*/
protected $arguments = array();
public function getArguments() {
return $this->arguments;
}
@@ -43,6 +47,7 @@ class MigrateGroup {
* @var array
*/
protected $dependencies = array();
public function getDependencies() {
return $this->dependencies;
}
@@ -53,6 +58,7 @@ class MigrateGroup {
* @var array
*/
static protected $groupList = array();
static public function groups() {
$groups = array();
$dependent_groups = array();
@@ -110,10 +116,10 @@ class MigrateGroup {
static public function getInstance($name, $dependencies = array()) {
if (empty(self::$groupList[$name])) {
$row = db_select('migrate_group', 'mg')
->fields('mg')
->condition('name', $name)
->execute()
->fetchObject();
->fields('mg')
->condition('name', $name)
->execute()
->fetchObject();
if ($row) {
$arguments = unserialize($row->arguments);
$arguments = MigrationBase::decryptArguments($arguments);
@@ -141,8 +147,8 @@ class MigrateGroup {
* A user-visible title for the group. Defaults to the machine name.
*
* @param array $arguments
* An array of group arguments - generally data that applies to all migrations
* in the group.
* An array of group arguments - generally data that applies to all
* migrations in the group.
*/
static public function register($name, $title = NULL, array $arguments = array()) {
if (!$title) {
@@ -156,9 +162,9 @@ class MigrateGroup {
db_merge('migrate_group')
->key(array('name' => $name))
->fields(array(
'title' => $title,
'arguments' => serialize($arguments)
))
'title' => $title,
'arguments' => serialize($arguments),
))
->execute();
}
@@ -172,9 +178,9 @@ class MigrateGroup {
*/
static public function deregister($name) {
$result = db_select('migrate_status', 'ms')
->fields('ms', array('machine_name'))
->condition('group_name', $name)
->execute();
->fields('ms', array('machine_name'))
->condition('group_name', $name)
->execute();
foreach ($result as $row) {
Migration::deregisterMigration($row->machine_name);
}

View File

@@ -10,12 +10,15 @@
* to implement appropriate methods (e.g., prepare, complete, or fields).
*/
abstract class MigrateHandler {
/**
* List of other handler classes which should be invoked before the current one.
* List of other handler classes which should be invoked before the current
* one.
*
* @var array
*/
protected $dependencies = array();
public function getDependencies() {
return $this->dependencies;
}
@@ -27,6 +30,7 @@ abstract class MigrateHandler {
* @var array
*/
protected $typesHandled = array();
public function getTypesHandled() {
return $this->typesHandled;
}

View File

@@ -10,12 +10,16 @@
* for the purpose of rollback.
*/
abstract class MigrateMap implements Iterator {
/**
* Codes reflecting the current status of a map row.
*/
const STATUS_IMPORTED = 0;
const STATUS_NEEDS_UPDATE = 1;
const STATUS_IGNORED = 2;
const STATUS_FAILED = 3;
/**
@@ -23,6 +27,7 @@ abstract class MigrateMap implements Iterator {
*
*/
const ROLLBACK_DELETE = 0;
const ROLLBACK_PRESERVE = 1;
/**
@@ -32,7 +37,9 @@ abstract class MigrateMap implements Iterator {
* @var array
*/
protected $sourceKey, $destinationKey;
abstract public function getSourceKey();
abstract public function getDestinationKey();
/**
@@ -56,9 +63,11 @@ abstract class MigrateMap implements Iterator {
* @var boolean
*/
protected $trackLastImported = FALSE;
public function getTrackLastImported() {
return $this->trackLastImported;
}
public function setTrackLastImported($trackLastImported) {
if (is_bool($trackLastImported)) {
$this->trackLastImported = $trackLastImported;
@@ -76,8 +85,8 @@ abstract class MigrateMap implements Iterator {
* @param $hash
*/
abstract public function saveIDMapping(stdClass $source_row, array $dest_ids,
$status = MigrateMap::STATUS_IMPORTED,
$rollback_action = MigrateMap::ROLLBACK_DELETE, $hash = NULL);
$status = MigrateMap::STATUS_IMPORTED,
$rollback_action = MigrateMap::ROLLBACK_DELETE, $hash = NULL);
/**
* Record a message related to a source record
@@ -147,6 +156,7 @@ abstract class MigrateMap implements Iterator {
* Retrieve map data for a given source or destination item
*/
abstract public function getRowBySource(array $source_id);
abstract public function getRowByDestination(array $destination_id);
/**
@@ -155,29 +165,32 @@ abstract class MigrateMap implements Iterator {
abstract public function getRowsNeedingUpdate($count);
/**
* Given a (possibly multi-field) destination key, return the (possibly multi-field)
* source key mapped to it.
* Given a (possibly multi-field) destination key, return the (possibly
* multi-field) source key mapped to it.
*
* @param array $destination_id
* Array of destination key values.
*
* @return array
* Array of source key values, or NULL on failure.
*/
abstract public function lookupSourceID(array $destination_id);
/**
* Given a (possibly multi-field) source key, return the (possibly multi-field)
* destination key it is mapped to.
* Given a (possibly multi-field) source key, return the (possibly
* multi-field) destination key it is mapped to.
*
* @param array $source_id
* Array of source key values.
*
* @return array
* Array of destination key values, or NULL on failure.
*/
abstract public function lookupDestinationID(array $source_id);
/**
* Remove any persistent storage used by this map (e.g., map and message tables)
* Remove any persistent storage used by this map (e.g., map and message
* tables)
*/
abstract public function destroy();
}

View File

@@ -8,20 +8,24 @@
/**
* The base class for all import objects. This is where most of the smarts
* of the migrate module resides. Migrations are created by deriving from this
* class, and in the constructor (after calling parent::__construct()) initializing
* at a minimum the name, description, source, and destination properties. The constructor
* will also usually make several calls to addFieldMapping().
* class, and in the constructor (after calling parent::__construct())
* initializing at a minimum the name, description, source, and destination
* properties. The constructor will also usually make several calls to
* addFieldMapping().
*/
abstract class Migration extends MigrationBase {
/**
* Source object for the migration, derived from MigrateSource.
*
* @var MigrateSource
*/
protected $source;
public function getSource() {
return $this->source;
}
public function setSource(MigrateSource $source) {
$this->source = $source;
}
@@ -32,9 +36,11 @@ abstract class Migration extends MigrationBase {
* @var MigrateDestination
*/
protected $destination;
public function getDestination() {
return $this->destination;
}
public function setDestination(MigrateDestination $destination) {
$this->destination = $destination;
}
@@ -45,9 +51,11 @@ abstract class Migration extends MigrationBase {
* @var MigrateMap
*/
protected $map;
public function getMap() {
return $this->map;
}
public function setMap(MigrateMap $map) {
$this->map = $map;
}
@@ -63,11 +71,15 @@ abstract class Migration extends MigrationBase {
* @var int
*/
const SOURCE = 1;
const DESTINATION = 2;
protected $systemOfRecord = Migration::SOURCE;
public function getSystemOfRecord() {
return $this->systemOfRecord;
}
public function setSystemOfRecord($system_of_record) {
$this->systemOfRecord = $system_of_record;
}
@@ -87,9 +99,11 @@ abstract class Migration extends MigrationBase {
* @var int
*/
protected $defaultRollbackAction = MigrateMap::ROLLBACK_DELETE;
public function getDefaultRollbackAction() {
return $this->defaultRollbackAction;
}
public function setDefaultRollbackAction($rollback_action) {
$this->defaultRollbackAction = $rollback_action;
}
@@ -107,7 +121,9 @@ abstract class Migration extends MigrationBase {
* @var array
*/
protected $storedFieldMappings = array();
protected $storedFieldMappingsRetrieved = FALSE;
public function getStoredFieldMappings() {
if (!$this->storedFieldMappingsRetrieved) {
$this->loadFieldMappings();
@@ -122,6 +138,7 @@ abstract class Migration extends MigrationBase {
* @var array
*/
protected $codedFieldMappings = array();
public function getCodedFieldMappings() {
return $this->codedFieldMappings;
}
@@ -133,10 +150,11 @@ abstract class Migration extends MigrationBase {
* @var array
*/
protected $allFieldMappings = array();
public function getFieldMappings() {
if (empty($allFieldMappings)) {
$this->allFieldMappings = array_merge($this->getCodedFieldMappings(),
$this->getStoredFieldMappings());
$this->getStoredFieldMappings());
// If there are multiple mappings of a given source field to no
// destination field, keep only the last (so the UI can override a source
// field DNM that was defined in code).
@@ -193,21 +211,25 @@ abstract class Migration extends MigrationBase {
* @var array
*/
protected $highwaterField = array();
public function getHighwaterField() {
return $this->highwaterField;
}
public function setHighwaterField(array $highwater_field) {
$this->highwaterField = $highwater_field;
}
/**
* The object currently being constructed
*
* @var stdClass
*/
protected $destinationValues;
/**
* The current data row retrieved from the source.
*
* @var stdClass
*/
protected $sourceValues;
@@ -238,7 +260,7 @@ abstract class Migration extends MigrationBase {
* @param array $arguments
*/
static public function registerMigration($class_name, $machine_name = NULL,
array $arguments = array()) {
array $arguments = array()) {
// Record any field mappings provided via arguments.
if (isset($arguments['field_mappings'])) {
self::saveFieldMappings($machine_name, $arguments['field_mappings']);
@@ -270,14 +292,13 @@ abstract class Migration extends MigrationBase {
// Remove stored field mappings for this migration
$rows_deleted = db_delete('migrate_field_mapping')
->condition('machine_name', $machine_name)
->execute();
->condition('machine_name', $machine_name)
->execute();
// Call the parent deregistration (which clears migrate_status) last, the
// above will reference it.
parent::deregisterMigration($machine_name);
}
catch (Exception $e) {
} catch (Exception $e) {
// Fail silently if it's already gone
}
}
@@ -298,11 +319,11 @@ abstract class Migration extends MigrationBase {
$source_field = $field_mapping->getSourceField();
db_insert('migrate_field_mapping')
->fields(array(
'machine_name' => $machine_name,
'destination_field' => is_null($destination_field) ? '' : $destination_field,
'source_field' => is_null($source_field) ? '' : $source_field,
'options' => serialize($field_mapping)
))
'machine_name' => $machine_name,
'destination_field' => is_null($destination_field) ? '' : $destination_field,
'source_field' => is_null($source_field) ? '' : $source_field,
'options' => serialize($field_mapping),
))
->execute();
}
}
@@ -312,9 +333,9 @@ abstract class Migration extends MigrationBase {
*/
public function loadFieldMappings() {
$result = db_select('migrate_field_mapping', 'mfm')
->fields('mfm', array('destination_field', 'source_field', 'options'))
->condition('machine_name', $this->machineName)
->execute();
->fields('mfm', array('destination_field', 'source_field', 'options'))
->condition('machine_name', $this->machineName)
->execute();
foreach ($result as $row) {
$field_mapping = unserialize($row->options);
$field_mapping->setMappingSource(MigrateFieldMapping::MAPPING_SOURCE_DB);
@@ -346,11 +367,14 @@ abstract class Migration extends MigrationBase {
$warn_on_override = TRUE) {
// Warn of duplicate mappings
if ($warn_on_override && !is_null($destination_field) &&
isset($this->codedFieldMappings[$destination_field])) {
isset($this->codedFieldMappings[$destination_field])) {
self::displayMessage(
t('!name addFieldMapping: !dest was previously mapped from !source, overridden',
array('!name' => $this->machineName, '!dest' => $destination_field,
'!source' => $this->codedFieldMappings[$destination_field]->getSourceField())),
array(
'!name' => $this->machineName,
'!dest' => $destination_field,
'!source' => $this->codedFieldMappings[$destination_field]->getSourceField(),
)),
'warning');
}
$mapping = new MigrateFieldMapping($destination_field, $source_field);
@@ -413,7 +437,7 @@ abstract class Migration extends MigrationBase {
}
foreach ($fields as $field) {
$this->addFieldMapping($field, NULL, $warn_on_override)
->issueGroup($issue_group);
->issueGroup($issue_group);
}
}
@@ -433,7 +457,7 @@ abstract class Migration extends MigrationBase {
}
foreach ($fields as $field) {
$this->addFieldMapping(NULL, $field, $warn_on_override)
->issueGroup($issue_group);
->issueGroup($issue_group);
}
}
@@ -464,7 +488,7 @@ abstract class Migration extends MigrationBase {
// Do some standard setup
if (isset($this->options['feedback']) && isset($this->options['feedback']['value']) &&
isset($this->options['feedback']['unit'])) {
isset($this->options['feedback']['unit'])) {
$this->feedback = $this->options['feedback']['value'];
$this->feedback_unit = $this->options['feedback']['unit'];
if ($this->feedback_unit == 'item') {
@@ -477,7 +501,7 @@ abstract class Migration extends MigrationBase {
$this->lastfeedback = $this->starttime;
$this->total_processed = $this->total_successes =
$this->processed_since_feedback = $this->successes_since_feedback = 0;
$this->processed_since_feedback = $this->successes_since_feedback = 0;
// Call pre-process methods
if ($this->status == Migration::STATUS_IMPORTING) {
@@ -572,7 +596,7 @@ abstract class Migration extends MigrationBase {
// Note that bulk rollback is only supported for single-column keys
$sourceids[] = $current_source_key;
if (!empty($destination_key->destid1)) {
$map_row = $this->map->getRowByDestination((array)$destination_key);
$map_row = $this->map->getRowByDestination((array) $destination_key);
if ($map_row['rollback_action'] == MigrateMap::ROLLBACK_DELETE) {
$destids[] = $destination_key->destid1;
}
@@ -594,8 +618,7 @@ abstract class Migration extends MigrationBase {
migrate_instrument_stop('rollback map/message update');
$this->total_successes += $batch_count;
$this->successes_since_feedback += $batch_count;
}
catch (Exception $e) {
} catch (Exception $e) {
$this->handleException($e, FALSE);
migrate_instrument_stop('bulkRollback');
migrate_instrument_stop('rollback map/message update');
@@ -656,10 +679,10 @@ abstract class Migration extends MigrationBase {
}
}
if (!$skip) {
$map_row = $this->map->getRowByDestination((array)$destination_key);
$map_row = $this->map->getRowByDestination((array) $destination_key);
if ($map_row['rollback_action'] == MigrateMap::ROLLBACK_DELETE) {
migrate_instrument_start('destination rollback');
$this->destination->rollback((array)$destination_key);
$this->destination->rollback((array) $destination_key);
migrate_instrument_stop('destination rollback');
}
}
@@ -670,8 +693,7 @@ abstract class Migration extends MigrationBase {
migrate_instrument_stop('rollback map/message update');
$this->total_successes++;
$this->successes_since_feedback++;
}
catch (Exception $e) {
} catch (Exception $e) {
// TODO: At least count failures
continue;
}
@@ -701,11 +723,15 @@ abstract class Migration extends MigrationBase {
try {
$this->source->rewind();
}
catch (Exception $e) {
} catch (Exception $e) {
self::displayMessage(
t('Migration failed with source plugin exception: %e, in %file:%line',
array('%e' => $e->getMessage(), '%file' => $e->getFile(), '%line' => $e->getLine())));
t('Migration for %class failed with source plugin exception: %e, in %file:%line',
array(
'%class' => get_class($this),
'%e' => $e->getMessage(),
'%file' => $e->getFile(),
'%line' => $e->getLine(),
)));
return MigrationBase::RESULT_FAILED;
}
while ($this->source->valid()) {
@@ -732,24 +758,22 @@ abstract class Migration extends MigrationBase {
else {
$this->map->saveIDMapping($this->sourceValues, array(),
MigrateMap::STATUS_FAILED, $this->rollbackAction,
$data_row->migrate_map_hash);
NULL);
if ($this->map->messageCount() == 0) {
$message = t('New object was not saved, no error provided');
$this->saveMessage($message);
self::displayMessage($message);
}
}
}
catch (MigrateException $e) {
} 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());
}
catch (Exception $e) {
} catch (Exception $e) {
$this->map->saveIDMapping($this->sourceValues, array(),
MigrateMap::STATUS_FAILED, $this->rollbackAction,
$data_row->migrate_map_hash);
NULL);
$this->handleException($e);
}
$this->total_processed++;
@@ -779,11 +803,15 @@ abstract class Migration extends MigrationBase {
}
try {
$this->source->next();
}
catch (Exception $e) {
} catch (Exception $e) {
self::displayMessage(
t('Migration failed with source plugin exception: %e, in %file:%line',
array('%e' => $e->getMessage(), '%file' => $e->getFile(), '%line' => $e->getLine())));
t('Migration for %class failed with source plugin exception: %e, in %file:%line',
array(
'%class' => get_class($this),
'%e' => $e->getMessage(),
'%file' => $e->getFile(),
'%line' => $e->getLine(),
)));
return MigrationBase::RESULT_FAILED;
}
}
@@ -805,8 +833,7 @@ abstract class Migration extends MigrationBase {
self::$currentMigration = $this;
try {
$this->source->rewind();
}
catch (Exception $e) {
} catch (Exception $e) {
self::displayMessage(
t('Migration analysis failed with source plugin exception: !e',
array('!e' => $e->getMessage())));
@@ -901,8 +928,7 @@ abstract class Migration extends MigrationBase {
try {
$this->source->next();
}
catch (Exception $e) {
} catch (Exception $e) {
self::displayMessage(
t('Migration analysis failed with source plugin exception: !e. Partial results follow:',
array('!e' => $e->getMessage())));
@@ -940,17 +966,18 @@ abstract class Migration extends MigrationBase {
public function prepareKey($source_key, $row) {
$key = array();
foreach ($source_key as $field_name => $field_schema) {
$key[$field_name] = $row->$field_name;
$key[$field_name] = $row->{$field_name};
}
return $key;
}
/**
* Default implementation of prepareRow(). This method is called from the source
* plugin upon first pulling the raw data from the source.
* Default implementation of prepareRow(). This method is called from the
* source plugin upon first pulling the raw data from the source.
*
* @param $row
* Object containing raw source data.
*
* @return bool
* TRUE to process this row, FALSE to have the source skip it.
*/
@@ -971,8 +998,7 @@ abstract class Migration extends MigrationBase {
public function sourceCount($refresh = FALSE) {
try {
$count = $this->source->count($refresh);
}
catch (Exception $e) {
} catch (Exception $e) {
$count = t('N/A');
self::displayMessage($e->getMessage());
}
@@ -981,14 +1007,14 @@ abstract class Migration extends MigrationBase {
/**
* Get the number of source records processed.
*
* @return int
* Number of processed records.
*/
public function processedCount() {
try {
$count = $this->map->processedCount();
}
catch (Exception $e) {
} catch (Exception $e) {
$count = t('N/A');
self::displayMessage($e->getMessage());
}
@@ -997,14 +1023,14 @@ abstract class Migration extends MigrationBase {
/**
* Get the number of records successfully imported.
*
* @return int
* Number of imported records.
*/
public function importedCount() {
try {
$count = $this->map->importedCount();
}
catch (Exception $e) {
} catch (Exception $e) {
$count = t('N/A');
self::displayMessage($e->getMessage());
}
@@ -1013,13 +1039,13 @@ abstract class Migration extends MigrationBase {
/**
* Get the number of records marked as needing update.
*
* @return int
*/
public function updateCount() {
try {
$count = $this->map->updateCount();
}
catch (Exception $e) {
} catch (Exception $e) {
$count = t('N/A');
self::displayMessage($e->getMessage());
}
@@ -1072,15 +1098,17 @@ abstract class Migration extends MigrationBase {
}
/**
* Outputs a progress message, reflecting the current status of a migration process.
* Outputs a progress message, reflecting the current status of a migration
* process.
*
* @param int $result
* Status of the process, represented by one of the Migration::RESULT_* constants.
* Status of the process, represented by one of the Migration::RESULT_*
* constants.
*/
protected function progressMessage($result) {
$time = microtime(TRUE) - $this->lastfeedback;
if ($time > 0) {
$perminute = round(60*$this->processed_since_feedback/$time);
$perminute = round(60 * $this->processed_since_feedback / $time);
$time = round($time, 1);
}
else {
@@ -1129,31 +1157,37 @@ abstract class Migration extends MigrationBase {
}
$numitems = $this->processed_since_feedback + $this->source->getIgnored();
$message = t($basetext,
array('!numitems' => $numitems,
'!successes' => $this->successes_since_feedback,
'!failed' => $this->processed_since_feedback - $this->successes_since_feedback,
'!created' => $this->destination->getCreated(),
'!updated' => $this->destination->getUpdated(),
'!ignored' => $this->source->getIgnored(),
'!time' => $time,
'!perminute' => $perminute,
'!name' => $this->machineName));
array(
'!numitems' => $numitems,
'!successes' => $this->successes_since_feedback,
'!failed' => $this->processed_since_feedback - $this->successes_since_feedback,
'!created' => $this->destination->getCreated(),
'!updated' => $this->destination->getUpdated(),
'!ignored' => $this->source->getIgnored(),
'!time' => $time,
'!perminute' => $perminute,
'!name' => $this->machineName,
));
self::displayMessage($message, $type);
// Report on lookup_cache hit rate. Only visible at 'debug' level.
if ($result != Migration::RESULT_INCOMPLETE && !empty($this->counts['lookup_cache'])) {
foreach ($this->counts['lookup_cache'] as $name => $tallies) {
$tallies += array('hit' => 0, 'miss_hit' => 0, 'miss_miss' => 0); // Set defaults to avoid NOTICE.
$sum = $tallies['hit']+$tallies['miss_hit']+$tallies['miss_miss'];
$tallies += array(
'hit' => 0,
'miss_hit' => 0,
'miss_miss' => 0,
); // Set defaults to avoid NOTICE.
$sum = $tallies['hit'] + $tallies['miss_hit'] + $tallies['miss_miss'];
self::displayMessage(
t('Lookup cache: !mn SM=!name !hit hit, !miss_hit miss_hit, !miss_miss miss_miss (!total total).', array(
'!mn' => $this->machineName,
'!name' => $name,
'!hit' => round((100*$tallies['hit'])/$sum) . '%',
'!miss_hit' => round((100*$tallies['miss_hit'])/$sum) . '%',
'!miss_miss' => round((100*$tallies['miss_miss'])/$sum) . '%',
'!total' => $sum
)), 'debug');
'!mn' => $this->machineName,
'!name' => $name,
'!hit' => round((100 * $tallies['hit']) / $sum) . '%',
'!miss_hit' => round((100 * $tallies['miss_hit']) / $sum) . '%',
'!miss_miss' => round((100 * $tallies['miss_miss']) / $sum) . '%',
'!total' => $sum,
)), 'debug');
}
$this->counts['lookup_cache'] = array();
}
@@ -1182,7 +1216,7 @@ abstract class Migration extends MigrationBase {
// If feedback is requested, produce a progress message at the proper time
if (isset($this->feedback)) {
if (($this->feedback_unit == 'seconds' && time() - $this->lastfeedback >= $this->feedback) ||
($this->feedback_unit == 'items' && $this->processed_since_feedback >= $this->feedback)) {
($this->feedback_unit == 'items' && $this->processed_since_feedback >= $this->feedback)) {
$this->progressMessage(MigrationBase::RESULT_INCOMPLETE);
}
}
@@ -1214,7 +1248,7 @@ abstract class Migration extends MigrationBase {
// If there's a source mapping, and a source value in the data row, copy
// to the destination
if ($source && isset($this->sourceValues->{$source})) {
$destination_values = $this->sourceValues->$source;
$destination_values = $this->sourceValues->{$source};
}
// Otherwise, apply the default value (if any)
elseif (!is_null($default)) {
@@ -1225,7 +1259,25 @@ abstract class Migration extends MigrationBase {
// will be populated as an array exploded from the source value
$separator = $mapping->getSeparator();
if ($separator && isset($destination_values)) {
$destination_values = explode($separator, $destination_values);
if (is_array($separator)) {
if (isset($separator['group separator'])) {
$destination_values = explode($separator['group separator'], $destination_values);
}
else {
$destination_values = array($destination_values);
}
foreach ($destination_values as $group => $value) {
if (isset($separator['key separator'])) {
$destination_values[$group] = explode($separator['key separator'], $value);
}
else {
$destination_values[$group] = array($value);
}
}
}
else {
$destination_values = explode($separator, $destination_values);
}
}
// If a source migration is supplied, use the current value for this field
@@ -1239,7 +1291,7 @@ abstract class Migration extends MigrationBase {
$callbacks = $mapping->getCallbacks();
foreach ($callbacks as $callback) {
if (isset($destination_values)) {
$destination_values = call_user_func($callback, $destination_values);
$destination_values = call_user_func_array($callback['callback'], array_merge(array($destination_values), $callback['params']));
}
}
@@ -1262,7 +1314,7 @@ abstract class Migration extends MigrationBase {
$destination_values['arguments'] = array();
foreach ($arguments as $argname => $destarg) {
if (is_array($destarg) && isset($destarg['source_field']) && property_exists($this->sourceValues, $destarg['source_field'])) {
$destination_values['arguments'][$argname] = $this->sourceValues->$destarg['source_field'];
$destination_values['arguments'][$argname] = $this->sourceValues->{$destarg['source_field']};
}
elseif (is_array($destarg) && isset($destarg['default_value'])) {
$destination_values['arguments'][$argname] = $destarg['default_value'];
@@ -1281,47 +1333,47 @@ abstract class Migration extends MigrationBase {
// last one.
$destination_count = count($destination);
$destination_field = $destination[0];
if ($destination_count == 2) {
if ($destination_count == 2) {
$subfield = $destination[1];
// We're processing the subfield before the primary value, initialize it
if (!property_exists($this->destinationValues, $destination_field)) {
$this->destinationValues->$destination_field = array();
$this->destinationValues->{$destination_field} = array();
}
// We have a value, and need to convert to an array so we can add
// arguments.
elseif (!is_array($this->destinationValues->$destination_field)) {
$this->destinationValues->$destination_field = array($this->destinationValues->$destination_field);
elseif (!is_array($this->destinationValues->{$destination_field})) {
$this->destinationValues->{$destination_field} = array($this->destinationValues->{$destination_field});
}
// Add the subfield value to the arguments array.
$this->destinationValues->{$destination_field}['arguments'][$subfield] = $destination_values;
}
elseif ($destination_count == 3) {
$subfield2 = $destination[2];
// We're processing the subfield before the primary value, initialize it
if (!property_exists($this->destinationValues, $destination_field)) {
$this->destinationValues->$destination_field = array();
}
// We have a value, and need to convert to an array so we can add
// arguments.
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]])) {
// 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]] );
}
// Add the subfield value to the arguments array.
$this->destinationValues->{$destination_field}['arguments'][$destination[1]]['arguments'][$subfield2] = $destination_values;
$subfield2 = $destination[2];
// We're processing the subfield before the primary value, initialize it
if (!property_exists($this->destinationValues, $destination_field)) {
$this->destinationValues->{$destination_field} = array();
}
// We have a value, and need to convert to an array so we can add
// arguments.
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]])) {
// 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]]);
}
// Add the subfield value to the arguments array.
$this->destinationValues->{$destination_field}['arguments'][$destination[1]]['arguments'][$subfield2] = $destination_values;
}
// Just the primary value, the first time through for this field, simply
// set it.
elseif (!property_exists($this->destinationValues, $destination_field)) {
$this->destinationValues->$destination_field = $destination_values;
$this->destinationValues->{$destination_field} = $destination_values;
}
// We've seen a subfield, so add as an array value.
else {
$this->destinationValues->{$destination_field} = array_merge(
(array)$destination_values, $this->destinationValues->{$destination_field});
(array) $destination_values, $this->destinationValues->{$destination_field});
}
}
}
@@ -1333,14 +1385,15 @@ abstract class Migration extends MigrationBase {
* @param mixed $source_migrations
* An array of source migrations, or string for a single migration.
* @param mixed $source_keys
* Key(s) to be looked up against the source migration(s). This may be a simple
* value (one single-field key), an array of values (multiple single-field keys
* to each be looked up), or an array of arrays (multiple multi-field keys to
* each be looked up).
* Key(s) to be looked up against the source migration(s). This may be a
* simple value (one single-field key), an array of values (multiple
* single-field keys to each be looked up), or an array of arrays (multiple
* multi-field keys to each be looked up).
* @param mixed $default
* The default value, if no ID was found.
* @param $migration
* The implementing migration.
*
* @return
* Destination value(s) from the source migration(s), as a single value if
* a single key was passed in, or an array of values if there were multiple
@@ -1377,6 +1430,11 @@ abstract class Migration extends MigrationBase {
// Instantiate each migration, and store back in the array.
foreach ($source_migrations as $key => $source_migration) {
$source_migrations[$key] = Migration::getInstance($source_migration);
if (!isset($source_migrations[$key])) {
MigrationBase::displayMessage(t('The @source cannot be resolved to a migration instance.',
array('@source' => $source_migration)));
unset($source_migrations[$key]);
}
}
$results = array();
@@ -1398,7 +1456,8 @@ abstract class Migration extends MigrationBase {
// Loop through each source migration, checking for an existing dest ID.
foreach ($source_migrations as $source_migration) {
// Break out of the loop as soon as a destination ID is found.
if ($destids = $source_migration->getMap()->lookupDestinationID($source_key)) {
if ($destids = $source_migration->getMap()
->lookupDestinationID($source_key)) {
if (!empty($destids['destid1'])) {
break;
}
@@ -1448,16 +1507,18 @@ abstract class Migration extends MigrationBase {
}
/**
* For fields which require uniqueness, assign a new unique value if necessary.
* For fields which require uniqueness, assign a new unique value if
* necessary.
*
* @param array $dedupe
* An array with two keys, 'table' the name of the Drupal table and 'column'
* the column within that table where uniqueness must be maintained.
* @param $original
* The value coming in, which must be checked for uniqueness.
*
* @return string
* The value to use - either the original, or a variation created by appending
* a sequence number.
* The value to use - either the original, or a variation created by
* appending a sequence number.
*/
protected function handleDedupe($dedupe, $original) {
// If we're remigrating a previously-existing value, simply running through
@@ -1468,11 +1529,11 @@ abstract class Migration extends MigrationBase {
if (isset($this->sourceValues->migrate_map_destid1)) {
$key_field = key($this->destination->getKeySchema());
$existing_value = db_select($dedupe['table'], 't')
->fields('t', array($dedupe['column']))
->range(0, 1)
->condition($key_field, $this->sourceValues->migrate_map_destid1)
->execute()
->fetchField();
->fields('t', array($dedupe['column']))
->range(0, 1)
->condition($key_field, $this->sourceValues->migrate_map_destid1)
->execute()
->fetchField();
// Note that if, for some reason, we don't find a value, fall through
// to the normal deduping process
if ($existing_value) {
@@ -1481,12 +1542,12 @@ abstract class Migration extends MigrationBase {
}
$i = 1;
$candidate = $original;
while ($candidate_found = db_select($dedupe['table'], 't')
->fields('t', array($dedupe['column']))
->range(0, 1)
->condition('t.' . $dedupe['column'], $candidate)
->execute()
->fetchField()) {
while (db_select($dedupe['table'], 't')
->fields('t', array($dedupe['column']))
->range(0, 1)
->condition('t.' . $dedupe['column'], $candidate)
->execute()
->rowCount() > 0) {
// We already have the candidate value. Find a non-existing value.
$i++;
// @TODO: support custom replacement pattern instead of just append.
@@ -1494,9 +1555,11 @@ abstract class Migration extends MigrationBase {
}
if ($i > 1) {
$message = t('Replacing !column !original with !candidate',
array('!column' => $dedupe['column'],
'!original' => $original,
'!candidate' => $candidate));
array(
'!column' => $dedupe['column'],
'!original' => $original,
'!candidate' => $candidate,
));
$migration = Migration::currentMigration();
$migration->saveMessage($message, Migration::MESSAGE_INFORMATIONAL);
}
@@ -1515,7 +1578,7 @@ abstract class Migration extends MigrationBase {
$data_row = new stdClass;
$i = 0;
foreach ($map_source_key as $key => $definition) {
$data_row->$key = $source_key[$i++];
$data_row->{$key} = $source_key[$i++];
}
$this->map->saveIDMapping($data_row, $destids,
MigrateMap::STATUS_NEEDS_UPDATE, $this->defaultRollbackAction);
@@ -1577,15 +1640,18 @@ abstract class Migration extends MigrationBase {
* Migration instead.
*/
abstract class DynamicMigration extends Migration {
static $deprecationWarning = FALSE;
public function __construct($arguments) {
parent::__construct($arguments);
if (variable_get('migrate_deprecation_warnings', 1) &&
!self::$deprecationWarning) {
!self::$deprecationWarning) {
self::displayMessage(t('The DynamicMigration class is no longer necessary and is now deprecated - please derive your migration classes directly from Migration.'));
self::$deprecationWarning = TRUE;
}
}
/**
* Overrides default of FALSE
*/

View File

@@ -13,6 +13,7 @@
* MigrateSourceSQL for an example.
*/
abstract class MigrateSource implements Iterator {
/**
* The current row from the quey
*
@@ -26,6 +27,7 @@ abstract class MigrateSource implements Iterator {
* @var array
*/
protected $currentKey;
public function getCurrentKey() {
return $this->currentKey;
}
@@ -50,6 +52,7 @@ abstract class MigrateSource implements Iterator {
* @var int
*/
protected $numIgnored = 0;
public function getIgnored() {
return $this->numIgnored;
}
@@ -60,6 +63,7 @@ abstract class MigrateSource implements Iterator {
* @var int
*/
protected $numProcessed = 0;
public function getProcessed() {
return $this->numProcessed;
}
@@ -160,7 +164,7 @@ abstract class MigrateSource implements Iterator {
}
if (!isset($this->cacheKey)) {
$this->cacheKey = md5((string)$this);
$this->cacheKey = md5((string) $this);
}
// If a refresh is requested, or we're not caching counts, ask the derived
@@ -227,17 +231,18 @@ abstract class MigrateSource implements Iterator {
}
/**
* Implementation of Iterator::key - called when entering a loop iteration, returning
* the key of the current row. It must be a scalar - we will serialize
* to fulfill the requirement, but using getCurrentKey() is preferable.
* Implementation of Iterator::key - called when entering a loop iteration,
* returning the key of the current row. It must be a scalar - we will
* serialize to fulfill the requirement, but using getCurrentKey() is
* preferable.
*/
public function key() {
return serialize($this->currentKey);
}
/**
* Implementation of Iterator::valid() - called at the top of the loop, returning
* TRUE to process the loop and FALSE to terminate it
* Implementation of Iterator::valid() - called at the top of the loop,
* returning TRUE to process the loop and FALSE to terminate it
*/
public function valid() {
return !is_null($this->currentRow);
@@ -292,7 +297,7 @@ abstract class MigrateSource implements Iterator {
if ($map_row) {
foreach ($map_row as $field => $value) {
$field = 'migrate_map_' . $field;
$row->$field = $value;
$row->{$field} = $value;
}
}
}
@@ -422,12 +427,12 @@ abstract class MigrateSource implements Iterator {
// so we need to provide them with the necessary information (before and
// after hashes).
if ($this->trackChanges) {
$unhashed_row = clone ($row);
$unhashed_row = clone $row;
// Remove all map data, otherwise we'll have a false positive on the
// second import (attempt) on a row.
foreach ($unhashed_row as $field => $data) {
if (strpos($field, 'migrate_map_') === 0) {
unset($unhashed_row->$field);
unset($unhashed_row->{$field});
}
}
$row->migrate_map_original_hash = isset($row->migrate_map_hash) ?

View File

@@ -7,17 +7,21 @@
*/
class MigrateTeamMember {
protected $name;
public function getName() {
return $this->name;
}
protected $emailAddress;
public function getEmailAddress() {
return $this->emailAddress;
}
protected $group;
public function getGroup() {
return $this->group;
}

View File

@@ -6,7 +6,8 @@
*/
/**
* Registers your module as an implementor of Migrate-based classes and provides
* Registers your module as an implementor of Migrate-based classes and
* provides
* default configuration for migration processes.
*
* @return
@@ -14,14 +15,16 @@
* required):
* - api: Always 2 for any module implementing the Migrate 2 API.
* - groups: An associative array, keyed by group machine name, defining one
* or more migration groups. Each value is an associative array - the 'title'
* key defines a user-visible name for the group; any other values are
* passed as arguments to all migrations in the group.
* or more migration groups. Each value is an associative array - the
* 'title' key defines a user-visible name for the group; any other values
* are passed as arguments to all migrations in the group.
* - migrations: An associative array, keyed by migration machine name,
* defining one or more migrations. Each value is an associative array - any
* defining one or more migrations. Each value is an associative array -
* any
* keys other than the following are passed as arguments to the migration
* constructor:
* - class_name (required): The name of the class implementing the migration.
* - class_name (required): The name of the class implementing the
* migration.
* - group_name: The machine name of the group containing the migration.
* - disable_hooks: An associative array, keyed by hook name, listing hook
* implementations to be disabled during migration. Each value is an

View File

@@ -175,8 +175,10 @@ function migrate_drush_command() {
);
$items['migrate-stop'] = array(
'description' => 'Stop an active migration operation',
'options' => array('all' => 'Stop all active migration operations',
'group' => 'Name of a specific migration group to stop'),
'options' => array(
'all' => 'Stop all active migration operations',
'group' => 'Name of a specific migration group to stop',
),
'arguments' => array(
'migration' => 'Name of migration to stop',
),
@@ -215,6 +217,7 @@ function migrate_drush_command() {
'migrate-deregister --group=myblog' => 'Deregister the myblog group and all migrations within it',
),
'drupal dependencies' => array('migrate'),
'aliases' => array('mdreg'),
);
$items['migrate-auto-register'] = array(
'description' => 'Register any newly defined migration classes',
@@ -229,7 +232,7 @@ function migrate_drush_command() {
$items['migrate-wipe'] = array(
'description' => 'Delete all nodes from specified content types.',
'examples' => array(
"migrate-wipe story article" => 'Delete all story and article nodes.',
"migrate-wipe story article" => 'Delete all story and article nodes.',
),
'arguments' => array(
'type' => 'A space delimited list of content type machine readable Ids.',
@@ -328,13 +331,21 @@ function drush_migrate_status($name = NULL) {
// An empty line and the headers.
$table[] = array('');
if ($names_only) {
$table[] = array(dt('Group: !name',
array('!name' => $group->getName())));
$table[] = array(
dt('Group: !name',
array('!name' => $group->getName())),
);
}
else {
$table[] = array(dt('Group: !name',
array('!name' => $group->getName())), dt('Total'), dt('Imported'),
dt('Unprocessed'), dt('Status'), dt('Last imported'));
$table[] = array(
dt('Group: !name',
array('!name' => $group->getName())),
dt('Total'),
dt('Imported'),
dt('Unprocessed'),
dt('Status'),
dt('Last imported'),
);
}
}
if (!$names_only) {
@@ -385,7 +396,14 @@ function drush_migrate_status($name = NULL) {
$status = dt('Unknown');
break;
}
$table[] = array($migration->getMachineName(), $total, $imported, $unimported, $status, $migration->getLastImported());
$table[] = array(
$migration->getMachineName(),
$total,
$imported,
$unimported,
$status,
$migration->getLastImported(),
);
}
else {
$table[] = array($migration->getMachineName());
@@ -393,8 +411,7 @@ function drush_migrate_status($name = NULL) {
}
}
drush_print_table($table);
}
catch (MigrateException $e) {
} catch (MigrateException $e) {
drush_print($e->getMessage());
exit;
}
@@ -419,8 +436,7 @@ function drush_migrate_fields_destination($args = NULL) {
drush_print(dt('No fields were found.'));
}
}
}
catch (MigrateException $e) {
} catch (MigrateException $e) {
drush_print($e->getMessage());
exit;
}
@@ -444,8 +460,7 @@ function drush_migrate_fields_source($args = NULL) {
drush_print(dt('No fields were found.'));
}
}
}
catch (MigrateException $e) {
} catch (MigrateException $e) {
drush_print($e->getMessage());
exit;
}
@@ -509,12 +524,22 @@ function drush_migrate_mappings($args = NULL) {
// Put out each group header
$table = array();
if ($full) {
$table[] = array(dt('Destination'), dt(''), dt('Source'), dt(''), dt('Default'),
dt('Description'));
$table[] = array(
dt('Destination'),
dt(''),
dt('Source'),
dt(''),
dt('Default'),
dt('Description'),
);
}
else {
$table[] = array(dt('Destination'), dt('Source'), dt('Default'),
dt('Description'));
$table[] = array(
dt('Destination'),
dt('Source'),
dt('Default'),
dt('Description'),
);
}
$first = TRUE;
@@ -550,12 +575,22 @@ function drush_migrate_mappings($args = NULL) {
else {
$src_description = '';
}
$table[] = array($destination, $dest_description, $source, $src_description,
$default, $mapping->getDescription());
$table[] = array(
$destination,
$dest_description,
$source,
$src_description,
$default,
$mapping->getDescription(),
);
}
else {
$table[] = array($destination, $source,
$default, $mapping->getDescription());
$table[] = array(
$destination,
$source,
$default,
$mapping->getDescription(),
);
}
}
}
@@ -569,8 +604,7 @@ function drush_migrate_mappings($args = NULL) {
}
}
}
}
catch (MigrateException $e) {
} catch (MigrateException $e) {
drush_print($e->getMessage());
exit;
}
@@ -590,8 +624,8 @@ function drush_migrate_messages($migration_name) {
$map = $migration->getMap();
$message_table = $map->getMessageTable();
$result = db_select($message_table, 'msg', array('fetch' => PDO::FETCH_ASSOC))
->fields('msg')
->execute();
->fields('msg')
->execute();
$first = TRUE;
$table = array();
foreach ($result as $row) {
@@ -621,8 +655,7 @@ function drush_migrate_messages($migration_name) {
drush_print_table($table, TRUE, $widths);
}
}
}
catch (MigrateException $e) {
} catch (MigrateException $e) {
drush_print($e->getMessage());
exit;
}
@@ -641,8 +674,10 @@ function drush_migrate_analyze($args = NULL) {
if (!empty($analysis)) {
foreach ($analysis as $field_name => $details) {
if (!empty($details['description'])) {
drush_print(dt('@name (@description):', array('@name' => $field_name,
'@description' => $details['description'])));
drush_print(dt('@name (@description):', array(
'@name' => $field_name,
'@description' => $details['description'],
)));
}
else {
drush_print(dt('@name:', array('@name' => $field_name)));
@@ -655,17 +690,23 @@ function drush_migrate_analyze($args = NULL) {
}
else {
drush_print(' ' . dt('Only one value present: @value',
array('@value' => $value)));
array('@value' => $value)));
}
}
else {
if ($details['is_numeric']) {
drush_print(' ' . dt('Numeric field with a range of @min to @max',
array('@min' => $details['min_numeric'], '@max' => $details['max_numeric'])));
array(
'@min' => $details['min_numeric'],
'@max' => $details['max_numeric'],
)));
}
else {
drush_print(' ' . dt('String field with a length ranging from @min to @max',
array('@min' => $details['min_strlen'], '@max' => $details['max_strlen'])));
array(
'@min' => $details['min_strlen'],
'@max' => $details['max_strlen'],
)));
}
$values = array();
$header = NULL;
@@ -781,10 +822,16 @@ function drush_migrate_audit($args = NULL) {
}
foreach (array_diff_key($source_fields, $used_sources) as $name => $description) {
$problems['sources_unmapped'][] = array('Field' => $name, 'Description' => $description);
$problems['sources_unmapped'][] = array(
'Field' => $name,
'Description' => $description,
);
}
foreach (array_diff_key($destination_fields, $used_destinations) as $name => $description) {
$problems['destinations_unmapped'][] = array('Field' => $name, 'Description' => $description);
$problems['destinations_unmapped'][] = array(
'Field' => $name,
'Description' => $description,
);
}
$problems = array_filter($problems);
@@ -810,8 +857,7 @@ function drush_migrate_audit($args = NULL) {
}
}
}
}
catch (MigrateException $e) {
} catch (MigrateException $e) {
drush_print($e->getMessage());
exit;
}
@@ -849,9 +895,9 @@ function drush_migrate_rollback($args = NULL) {
$options['limit']['unit'] = 'items';
}
elseif ($options['limit']['unit'] != 'seconds' &&
$options['limit']['unit'] != 'second' &&
$options['limit']['unit'] != 'items' &&
$options['limit']['unit'] != 'item') {
$options['limit']['unit'] != 'second' &&
$options['limit']['unit'] != 'items' &&
$options['limit']['unit'] != 'item') {
drush_set_error(NULL, dt("Invalid limit unit '!unit'",
array('!unit' => $options['limit']['unit'])));
return;
@@ -864,9 +910,9 @@ function drush_migrate_rollback($args = NULL) {
$options['feedback']['value'] = $parts[0];
$options['feedback']['unit'] = $parts[1];
if ($options['feedback']['unit'] != 'seconds' &&
$options['feedback']['unit'] != 'second' &&
$options['feedback']['unit'] != 'items' &&
$options['feedback']['unit'] != 'item') {
$options['feedback']['unit'] != 'second' &&
$options['feedback']['unit'] != 'items' &&
$options['feedback']['unit'] != 'item') {
drush_set_error(NULL, dt("Invalid feedback frequency unit '!unit'",
array('!unit' => $options['feedback']['unit'])));
return;
@@ -907,8 +953,7 @@ function drush_migrate_rollback($args = NULL) {
'warning');
}
}
}
catch (MigrateException $e) {
} catch (MigrateException $e) {
drush_print($e->getMessage());
exit;
}
@@ -966,8 +1011,8 @@ function drush_migrate_get_migrations($args) {
elseif ($group = drush_get_option('group')) {
foreach ($migration_objects as $name => $migration) {
if (drupal_strtolower($group) !=
drupal_strtolower($migration->getGroup()->getName()) ||
!$migration->getEnabled()) {
drupal_strtolower($migration->getGroup()->getName()) ||
!$migration->getEnabled()) {
unset($migration_objects[$name]);
}
}
@@ -1075,10 +1120,10 @@ function drush_migrate_validate_common($args) {
foreach ($machine_names as $machine_name) {
$machine_name = trim($machine_name);
$class_name = db_select('migrate_status', 'ms')
->fields('ms', array('class_name'))
->condition('machine_name', $machine_name)
->execute()
->fetchField();
->fields('ms', array('class_name'))
->condition('machine_name', $machine_name)
->execute()
->fetchField();
if (!$class_name || !class_exists($class_name)) {
drush_set_error(dt('Unrecognized migration: !name', array('!name' => $machine_name)));
}
@@ -1091,9 +1136,9 @@ function drush_migrate_validate_common($args) {
$options['feedback']['value'] = $parts[0];
$options['feedback']['unit'] = $parts[1];
if ($options['feedback']['unit'] != 'seconds' &&
$options['feedback']['unit'] != 'second' &&
$options['feedback']['unit'] != 'items' &&
$options['feedback']['unit'] != 'item') {
$options['feedback']['unit'] != 'second' &&
$options['feedback']['unit'] != 'items' &&
$options['feedback']['unit'] != 'item') {
drush_set_error(NULL, dt("Invalid feedback frequency unit '!unit'",
array('!unit' => $options['feedback']['unit'])));
return;
@@ -1114,19 +1159,18 @@ function drush_migrate_pre_migrate_import($args = NULL) {
foreach ($migrations as $migration) {
$status = $migration->getStatus();
if ($status == MigrationBase::STATUS_IMPORTING ||
$status == MigrationBase::STATUS_ROLLING_BACK) {
$status == MigrationBase::STATUS_ROLLING_BACK) {
drush_log(dt("Stopping '!description' migration", array('!description' => $migration->getMachineName())));
$migration->stopProcess();
// Give the process a chance to stop.
$count = 0;
while ($migration->getStatus() != MigrationBase::STATUS_IDLE
&& $count++ < 5) {
&& $count++ < 5) {
sleep(1);
}
}
}
}
catch (MigrateException $e) {
} catch (MigrateException $e) {
drush_print($e->getMessage());
exit;
}
@@ -1144,6 +1188,8 @@ function drush_migrate_pre_migrate_import($args = NULL) {
* A comma delimited list of machine names, or the special name 'all'
*/
function drush_migrate_import($args = NULL) {
$status = NULL;
try {
if (drush_get_option('notify', FALSE)) {
// Capture non-informational output for mailing
@@ -1165,14 +1211,18 @@ function drush_migrate_import($args = NULL) {
if ($limit) {
$parts = explode(' ', $limit);
$options['limit']['value'] = $parts[0];
$options['limit']['unit'] = $parts[1];
if (!$options['limit']['unit']) {
$options['limit']['unit'] = 'items';
// Default unit.
if (!isset($parts[1])) {
$parts[1] = 'items';
}
elseif ($options['limit']['unit'] != 'seconds' &&
$options['limit']['unit'] != 'second' &&
$options['limit']['unit'] != 'items' &&
$options['limit']['unit'] != 'item') {
$options['limit']['unit'] = $parts[1];
// Validation.
if (!in_array($options['limit']['unit'], array(
'seconds',
'second',
'items',
'item',
))) {
drush_set_error(NULL, dt("Invalid limit unit '!unit'",
array('!unit' => $options['limit']['unit'])));
return;
@@ -1184,9 +1234,9 @@ function drush_migrate_import($args = NULL) {
$options['feedback']['value'] = $parts[0];
$options['feedback']['unit'] = $parts[1];
if ($options['feedback']['unit'] != 'seconds' &&
$options['feedback']['unit'] != 'second' &&
$options['feedback']['unit'] != 'items' &&
$options['feedback']['unit'] != 'item') {
$options['feedback']['unit'] != 'second' &&
$options['feedback']['unit'] != 'items' &&
$options['feedback']['unit'] != 'item') {
drush_set_error(NULL, dt("Invalid feedback frequency unit '!unit'",
array('!unit' => $options['feedback']['unit'])));
return;
@@ -1282,8 +1332,10 @@ function drush_migrate_import($args = NULL) {
elseif ($status == MigrationBase::RESULT_INCOMPLETE) {
$stop = TRUE;
}
drush_backend_set_result(array('status' => $status,
'migrations' => implode(',', array_keys($migrations))));
drush_backend_set_result(array(
'status' => $status,
'migrations' => implode(',', array_keys($migrations)),
));
}
if ($stop) {
@@ -1291,8 +1343,7 @@ function drush_migrate_import($args = NULL) {
}
unset($migrations[$machine_name]);
}
}
catch (MigrateException $e) {
} catch (MigrateException $e) {
drush_print($e->getMessage());
exit;
}
@@ -1309,6 +1360,8 @@ function drush_migrate_import($args = NULL) {
if (drush_get_option('notify')) {
_drush_migrate_notify();
}
return $status;
}
/**
@@ -1324,8 +1377,7 @@ function drush_migrate_stop($args = NULL) {
drush_log(dt("Stopping '!description' migration", array('!description' => $migration->getMachineName())));
$migration->stopProcess();
}
}
catch (MigrateException $e) {
} catch (MigrateException $e) {
drush_print($e->getMessage());
exit;
}
@@ -1342,8 +1394,7 @@ function drush_migrate_reset_status($args = NULL) {
array('!description' => $migration->getMachineName())));
$migration->resetStatus();
}
}
catch (MigrateException $e) {
} catch (MigrateException $e) {
drush_print($e->getMessage());
exit;
}
@@ -1368,8 +1419,8 @@ function drush_migrate_deregister($args = NULL) {
if ($orphans) {
$migrations = array();
$result = db_select('migrate_status', 'ms')
->fields('ms', array('class_name', 'machine_name'))
->execute();
->fields('ms', array('class_name', 'machine_name'))
->execute();
foreach ($result as $row) {
if (!class_exists($row->class_name)) {
$migrations[] = $row->machine_name;
@@ -1385,8 +1436,7 @@ function drush_migrate_deregister($args = NULL) {
array('!description' => $machine_name)), 'success');
}
}
}
catch (MigrateException $e) {
} catch (MigrateException $e) {
drush_print($e->getMessage());
exit;
}
@@ -1435,10 +1485,10 @@ function drush_migrate_register($args = NULL) {
function drush_migrate_wipe() {
$types = func_get_args();
$nids = db_select('node', 'n')
->fields('n', array('nid'))
->condition('type', $types, 'IN')
->execute()
->fetchCol();
->fields('n', array('nid'))
->condition('type', $types, 'IN')
->execute()
->fetchCol();
$chunks = array_chunk($nids, 50);
foreach ($chunks as $chunk) {
node_delete_multiple($chunk);
@@ -1450,7 +1500,7 @@ function drush_migrate_wipe() {
function drush_migrate_print_memory() {
global $_migrate_memory;
$temparray = array();
foreach ((array)$_migrate_memory as $name => $memoryrec) {
foreach ((array) $_migrate_memory as $name => $memoryrec) {
// We have to use timer_read() for active timers, and check the record for others
if (isset($memoryrec['start'])) {
$temparray[$name] = migrate_memory_read($name);
@@ -1468,7 +1518,7 @@ function drush_migrate_print_memory() {
foreach ($temparray as $name => $memory) {
$count = $_migrate_memory[$name]['count'];
if ($count > 0) {
$avg = round($memory/$count, 0);
$avg = round($memory / $count, 0);
}
else {
$avg = 'N/A';

View File

@@ -51,9 +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 2015-07-01
version = "7.x-2.8"
; Information added by Drupal.org packaging script on 2018-06-10
version = "7.x-2.11"
core = "7.x"
project = "migrate"
datestamp = "1435760949"
datestamp = "1528674486"

View File

@@ -226,12 +226,12 @@ function migrate_uninstall() {
function migrate_update_7001() {
if (!db_field_exists('migrate_status', 'highwater')) {
db_add_field('migrate_status', 'highwater', array(
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => '',
'description' => 'Highwater mark for detecting updated content',
)
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => '',
'description' => 'Highwater mark for detecting updated content',
)
);
}
@@ -293,8 +293,8 @@ function migrate_update_7004() {
if (db_field_exists('migrate_status', 'lastimported')) {
$result = db_select('migrate_status', 'ms')
->fields('ms', array('machine_name', 'lastimported'))
->execute();
->fields('ms', array('machine_name', 'lastimported'))
->execute();
foreach ($result as $row) {
$lastimportedtime = strtotime($row->lastimported);
db_update('migrate_status')
@@ -334,12 +334,12 @@ function migrate_update_7006() {
$ret = '';
if (!db_field_exists('migrate_status', 'class_name')) {
db_add_field('migrate_status', 'class_name', array(
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => '',
'description' => 'Name of class to instantiate for this migration',
)
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => '',
'description' => 'Name of class to instantiate for this migration',
)
);
db_query("UPDATE {migrate_status}
@@ -357,12 +357,12 @@ function migrate_update_7007() {
$ret = '';
if (!db_field_exists('migrate_status', 'arguments')) {
db_add_field('migrate_status', 'arguments', array(
'type' => 'blob',
'not null' => FALSE,
'size' => 'big',
'serialize' => TRUE,
'description' => 'A serialized array of arguments to the migration constructor',
)
'type' => 'blob',
'not null' => FALSE,
'size' => 'big',
'serialize' => TRUE,
'description' => 'A serialized array of arguments to the migration constructor',
)
);
$ret = t('Added arguments column to migrate_status table');
@@ -394,18 +394,18 @@ function migrate_update_7008() {
$field = 'destid' . $index++;
$field_schema['not null'] = FALSE;
$map_connection->schema()->changeField($map_table, $field, $field,
$field_schema);
$field_schema);
$ret .= "\n" . t('Changed !table.!field to be non-null',
array('!table' => $map_table, '!field' => $field));
array('!table' => $map_table, '!field' => $field));
}
// Add any existing failures to the map table
$msg_table = $map->getMessageTable();
$msg_marked = FALSE;
$result = $map_connection->select($msg_table, 'msg')
->fields('msg')
->condition('level', Migration::MESSAGE_INFORMATIONAL, '<>')
->execute();
->fields('msg')
->condition('level', Migration::MESSAGE_INFORMATIONAL, '<>')
->execute();
foreach ($result as $row) {
$keys = array();
$index = 1;
@@ -415,9 +415,9 @@ function migrate_update_7008() {
}
}
$map_connection->merge($map_table)
->key($keys)
->fields(array('needs_update' => MigrateMap::STATUS_FAILED))
->execute();
->key($keys)
->fields(array('needs_update' => MigrateMap::STATUS_FAILED))
->execute();
$msg_marked = TRUE;
}
if ($msg_marked) {
@@ -472,14 +472,14 @@ function migrate_update_7203() {
db_create_table('migrate_group', migrate_schema_group());
}
if (!db_field_exists('migrate_status', 'group_name')) {
$ret .= t('Add group relationship to migrate_status table'). "\n";
$ret .= t('Add group relationship to migrate_status table') . "\n";
db_add_field('migrate_status', 'group_name', array(
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => 'default',
'description' => 'Name of group containing migration',
)
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => 'default',
'description' => 'Name of group containing migration',
)
);
// Populate each migration's group_name field
$groups = array();
@@ -497,17 +497,17 @@ function migrate_update_7203() {
// Populate the migrate_group table
foreach ($groups as $group_name) {
$title = db_select('migrate_group', 'mg')
->fields('mg', array('title'))
->condition('name', $group_name)
->execute()
->fetchField();
->fields('mg', array('title'))
->condition('name', $group_name)
->execute()
->fetchField();
if (!$title) {
db_insert('migrate_group')
->fields(array(
'name' => $group_name,
'title' => $group_name,
'arguments' => serialize(array()),
))
'name' => $group_name,
'title' => $group_name,
'arguments' => serialize(array()),
))
->execute();
}
}
@@ -559,20 +559,20 @@ function migrate_update_7206() {
*/
function migrate_update_7207() {
$rows = db_select('migrate_group', 'mg')
->fields('mg', array('name'))
->condition('name', 'default')
->execute()
->rowCount();
->fields('mg', array('name'))
->condition('name', 'default')
->execute()
->rowCount();
if ($rows > 0) {
$rows = db_select('migrate_status', 'ms')
->fields('ms', array('machine_name'))
->condition('group_name', 'default')
->execute()
->rowCount();
->fields('ms', array('machine_name'))
->condition('group_name', 'default')
->execute()
->rowCount();
if ($rows == 0) {
db_delete('migrate_group')
->condition('name', 'default')
->execute();
->condition('name', 'default')
->execute();
}
}
}

View File

@@ -6,6 +6,7 @@
*/
class MigrateMailIgnore extends DefaultMailSystem {
/**
* On an email request, do nothing and say we did.
*
@@ -14,6 +15,7 @@ class MigrateMailIgnore extends DefaultMailSystem {
*
* @param $message
* A message array, as described in hook_mail_alter().
*
* @return
* TRUE if the mail was successfully accepted, otherwise FALSE.
*/

View File

@@ -18,6 +18,28 @@ define('MIGRATE_API_VERSION', 2);
define('MIGRATE_ACCESS_BASIC', 'migration information');
define('MIGRATE_ACCESS_ADVANCED', 'advanced migration information');
/**
* Implements hook_help().
*/
function migrate_help($path, $arg) {
switch ($path) {
case 'admin/help#migrate':
$output = '';
$output .= '<h3>' . t('About') . '</h3>';
$output .= '<p>' . t('The Migrate module provides a flexible framework for migrating content into Drupal from other sources (e.g., when converting a web site from another CMS to Drupal). Out-of-the-box, support for creating Drupal nodes, taxonomy terms, comments, and users are included. Plugins permit migration of other types of content. For more information, see the online documentation for the <a href="@handbook">Migrate module</a>.', array('@handbook' => 'http://drupal.org/migrate')) . '</p>';
$output .= '<h3>' . t('Uses') . '</h3>';
$output .= '<dl>';
$output .= '<dt>' . t('Getting Started') . '</dt>';
$output .= '<dd>' . t('To get started, enable the migrate_example module and browse to admin/content/migrate to see its dashboard. The code for this migration is in migrate_example/beer.inc (advanced examples are in wine.inc). Mimic that file in order to specify your own migrations.') . '</dd>';
$output .= '<dt>' . t('Migrate Support') . '</dt>';
$output .= '<dd>' . t('The Migrate module itself has support for migration into core objects. Some built-in support for migration involving contrib modules is in the migrate_extras module.') . '</dd>';
$output .= '<dt>' . t('Migrate Extended Support') . '</dt>';
$output .= '<dd>' . t('The best place to implement migration support for a contributed module is in that module, not in the Migrate or Migrate Extras modules. That way, the migration support is always self-consistent with the current module implementation - it is not practical for the migrate modules to keep up with changes to all other contrib modules.') . '</dd>';
$output .= '</dl>';
return $output;
}
}
/**
* Retrieve a list of all active migrations, ordered by dependencies. To be
* recognized, a class must be non-abstract, and derived from MigrationBase.
@@ -45,8 +67,8 @@ function migrate_migrations($reset = NULL) {
$required_migrations = array();
$result = db_select('migrate_status', 'ms')
->fields('ms', array('machine_name', 'class_name'))
->execute();
->fields('ms', array('machine_name', 'class_name'))
->execute();
foreach ($result as $row) {
if (class_exists($row->class_name)) {
$reflect = new ReflectionClass($row->class_name);
@@ -68,12 +90,12 @@ function migrate_migrations($reset = NULL) {
}
else {
MigrationBase::displayMessage(t('Class !class is no longer a valid concrete migration class',
array('!class' => $row->class_name)));
array('!class' => $row->class_name)));
}
}
else {
MigrationBase::displayMessage(t('Class !class no longer exists',
array('!class' => $row->class_name)));
MigrationBase::displayMessage(t('Class !class could not be found',
array('!class' => $row->class_name)));
}
}
@@ -101,7 +123,8 @@ function migrate_migrations($reset = NULL) {
)));
}
else {
$final_migrations[$migration->getGroup()->getName()][$machine_name] = $migration;
$final_migrations[$migration->getGroup()
->getName()][$machine_name] = $migration;
}
}
// Flatten the grouped list.
@@ -124,8 +147,8 @@ function migrate_migrations($reset = NULL) {
* Destination type ('Node', 'User', etc.) - generally the same string as
* the destination class name without the MigrateDestination prefix.
* @param $method
* Method name such as 'prepare' (called at the beginning of an import operation)
* or 'complete' (called at the end of an import operation).
* Method name such as 'prepare' (called at the beginning of an import
* operation) or 'complete' (called at the end of an import operation).
* @param ...
* Parameters to be passed to the handler.
*/
@@ -138,7 +161,7 @@ function migrate_handler_invoke_all($destination, $method) {
$disabled = unserialize(variable_get('migrate_disabled_handlers', serialize(array())));
foreach ($class_list as $class_name => $handler) {
if (!in_array($class_name, $disabled) && $handler->handlesType($destination)
&& method_exists($handler, $method)) {
&& method_exists($handler, $method)) {
migrate_instrument_start($class_name . '->' . $method);
$result = call_user_func_array(array($handler, $method), $args);
migrate_instrument_stop($class_name . '->' . $method);
@@ -169,16 +192,16 @@ function migrate_handler_invoke_all($destination, $method) {
* Handler method to call (defaults to prepare()).
*/
function migrate_field_handler_invoke_all($entity, array $field_info,
array $instance, array $values, $method = 'prepare') {
array $instance, array $values, $method = 'prepare') {
$return = array();
$type = $field_info['type'];
$class_list = _migrate_class_list('MigrateFieldHandler');
$disabled = unserialize(variable_get('migrate_disabled_handlers',
serialize(array())));
serialize(array())));
$handler_called = FALSE;
foreach ($class_list as $class_name => $handler) {
if (!in_array($class_name, $disabled) && $handler->handlesType($type)
&& method_exists($handler, $method)) {
&& method_exists($handler, $method)) {
migrate_instrument_start($class_name . '->' . $method);
$result = call_user_func_array(array($handler, $method),
array($entity, $field_info, $instance, $values));
@@ -210,13 +233,15 @@ function migrate_field_handler_invoke_all($entity, array $field_info,
}
/**
* For a given parent class, identify and instantiate objects for any non-abstract
* classes derived from the parent, returning an array of the objects indexed by
* class name. The array will be ordered such that any classes with dependencies
* are listed after the classes they are dependent on.
* For a given parent class, identify and instantiate objects for any
* non-abstract classes derived from the parent, returning an array of the
* objects indexed by class name. The array will be ordered such that any
* classes with dependencies are listed after the classes they are dependent
* on.
*
* @param $parent_class
* Name of a class from which results will be derived.
*
* @return
* Array of objects, keyed by the class name.
*/
@@ -295,8 +320,11 @@ function migrate_get_module_apis($reset = FALSE) {
else {
drupal_set_message(t('%function supports Migrate API version %modversion,
Migrate module API version is %version - migration support not loaded.',
array('%function' => $function, '%modversion' => $info['api'],
'%version' => MIGRATE_API_VERSION)));
array(
'%function' => $function,
'%modversion' => $info['api'],
'%version' => MIGRATE_API_VERSION,
)));
}
}
@@ -448,6 +476,7 @@ function migrate_memory_start($name) {
*
* @param name
* The name of the memory measurement.
*
* @return
* The change in bytes since the last start.
*/
@@ -471,9 +500,11 @@ function migrate_memory_read($name) {
*
* @param name
* The name of the memory measurement.
*
* @return
* A memory array. The array contains the number of times the memory has been
* started and stopped (count) and the accumulated memory difference value in bytes.
* started and stopped (count) and the accumulated memory difference value in
* bytes.
*/
function migrate_memory_stop($name) {
global $_migrate_memory;
@@ -496,9 +527,9 @@ function migrate_memory_stop($name) {
}
/**
* Start measuring time and (optionally) memory consumption over a section of code.
* Note that the memory consumption measurement is generally not useful in
* lower areas of the code, where data is being generated that will be freed
* Start measuring time and (optionally) memory consumption over a section of
* code. Note that the memory consumption measurement is generally not useful
* in lower areas of the code, where data is being generated that will be freed
* by the next call to the same area. For example, measuring the memory
* consumption of db_query is not going to be helpful.
*
@@ -534,7 +565,8 @@ function migrate_instrument_stop($name) {
}
/**
* Call hook_migrate_overview for overall documentation on implemented migrations.
* Call hook_migrate_overview for overall documentation on implemented
* migrations.
*/
function migrate_overview() {
$overview = '';

View File

@@ -34,10 +34,12 @@
*
* In any serious migration project, you will find there are some options
* which are common to the individual migrations you're implementing. You can
* define an abstract intermediate class derived from Migration, then derive your
* individual migrations from that, to share settings, utility functions, etc.
* define an abstract intermediate class derived from Migration, then derive
* your individual migrations from that, to share settings, utility functions,
* etc.
*/
abstract class BasicExampleMigration extends Migration {
// A Migration constructor takes an array of arguments as its first parameter.
// The arguments must be passed through to the parent constructor.
public function __construct($arguments) {
@@ -48,9 +50,9 @@ abstract class BasicExampleMigration extends Migration {
// list in the shared class; it can be overridden for specific migrations.
$this->team = array(
new MigrateTeamMember('Liz Taster', 'ltaster@example.com',
t('Product Owner')),
t('Product Owner')),
new MigrateTeamMember('Larry Brewer', 'lbrewer@example.com',
t('Implementor')),
t('Implementor')),
);
// Individual mappings in a migration can be linked to a ticket or issue
@@ -76,6 +78,7 @@ abstract class BasicExampleMigration extends Migration {
* information associated with the mappings.
*/
class BeerTermMigration extends BasicExampleMigration {
public function __construct($arguments) {
parent::__construct($arguments);
// Human-friendly description of your migration process. Be as detailed as
@@ -91,10 +94,15 @@ class BeerTermMigration extends BasicExampleMigration {
// style_parent, we guarantee root terms are migrated first, so the
// parent_name mapping below will find that the parent exists.
$query = db_select('migrate_example_beer_topic', 'met')
->fields('met', array('style', 'details', 'style_parent', 'region',
'hoppiness'))
// This sort assures that parents are saved before children.
->orderBy('style_parent', 'ASC');
->fields('met', array(
'style',
'details',
'style_parent',
'region',
'hoppiness',
))
// This sort assures that parents are saved before children.
->orderBy('style_parent', 'ASC');
// Create a MigrateSource object, which manages retrieving the input data.
$this->source = new MigrateSourceSQL($query);
@@ -112,15 +120,16 @@ class BeerTermMigration extends BasicExampleMigration {
// destination - we need to be explicit for our source, but the destination
// class knows its schema already.
$this->map = new MigrateSQLMap($this->machineName,
array(
'style' => array('type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'description' => 'Topic ID',
)
array(
'style' => array(
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'description' => 'Topic ID',
),
MigrateDestinationTerm::getKeySchema()
);
),
MigrateDestinationTerm::getKeySchema()
);
// Assign mappings TO destination fields FROM source fields. To discover
// the names used in these calls, use the drush commands
@@ -133,7 +142,7 @@ class BeerTermMigration extends BasicExampleMigration {
// Documenting your mappings makes it easier for the whole team to see
// exactly what the status is when developing a migration process.
$this->addFieldMapping('parent_name', 'style_parent')
->description(t('The incoming style_parent field is the name of the term parent'));
->description(t('The incoming style_parent field is the name of the term parent'));
// Mappings are assigned issue groups, by which they are grouped on the
// migration info page when the migrate_ui module is enabled. The default
@@ -147,8 +156,8 @@ class BeerTermMigration extends BasicExampleMigration {
// necessary information, and now the implementor needs to complete the
// work.
$this->addFieldMapping(NULL, 'hoppiness')
->description(t('This info will not be maintained in Drupal'))
->issueGroup(t('DNM'));
->description(t('This info will not be maintained in Drupal'))
->issueGroup(t('DNM'));
// Open mapping issues can be assigned priorities (the default is
// MigrateFieldMapping::ISSUE_PRIORITY_OK). If you're using an issue
@@ -156,11 +165,11 @@ class BeerTermMigration extends BasicExampleMigration {
// above), you can specify a ticket/issue number in the system on the
// mapping and migrate_ui will link directly to it.
$this->addFieldMapping(NULL, 'region')
->description('Will a field be added to the vocabulary for this?')
->issueGroup(t('Client Issues'))
// This priority wil cause the mapping to be highlighted in the UI.
->issuePriority(MigrateFieldMapping::ISSUE_PRIORITY_MEDIUM)
->issueNumber(770064);
->description('Will a field be added to the vocabulary for this?')
->issueGroup(t('Client Issues'))
// This priority wil cause the mapping to be highlighted in the UI.
->issuePriority(MigrateFieldMapping::ISSUE_PRIORITY_MEDIUM)
->issueNumber(770064);
// It is good practice to account for all source and destination fields
// explicitly - this makes sure that everyone understands exactly what is
@@ -170,21 +179,21 @@ class BeerTermMigration extends BasicExampleMigration {
// immediately visible, and you can decide if anything needs to be
// migrated into it.
$this->addFieldMapping('format')
->issueGroup(t('DNM'));
->issueGroup(t('DNM'));
$this->addFieldMapping('weight')
->issueGroup(t('DNM'));
->issueGroup(t('DNM'));
$this->addFieldMapping('parent')
->issueGroup(t('DNM'));
->issueGroup(t('DNM'));
// We conditionally DNM these fields, so your field mappings will be clean
// whether or not you have path and/or pathauto enabled.
$destination_fields = $this->destination->fields();
if (isset($destination_fields['path'])) {
$this->addFieldMapping('path')
->issueGroup(t('DNM'));
->issueGroup(t('DNM'));
if (isset($destination_fields['pathauto'])) {
$this->addFieldMapping('pathauto')
->issueGroup(t('DNM'));
->issueGroup(t('DNM'));
}
}
}
@@ -201,23 +210,34 @@ class BeerTermMigration extends BasicExampleMigration {
* transformations of the data.
*/
class BeerUserMigration extends BasicExampleMigration {
public function __construct($arguments) {
// The basic setup is similar to BeerTermMigraiton
parent::__construct($arguments);
$this->description = t('Beer Drinkers of the world');
$query = db_select('migrate_example_beer_account', 'mea')
->fields('mea', array('aid', 'status', 'posted', 'name',
'nickname', 'password', 'mail', 'sex', 'beers'));
->fields('mea', array(
'aid',
'status',
'posted',
'name',
'nickname',
'password',
'mail',
'sex',
'beers',
));
$this->source = new MigrateSourceSQL($query);
$this->destination = new MigrateDestinationUser();
$this->map = new MigrateSQLMap($this->machineName,
array('aid' => array(
'type' => 'int',
'not null' => TRUE,
'description' => 'Account ID.'
)
array(
'aid' => array(
'type' => 'int',
'not null' => TRUE,
'description' => 'Account ID.',
),
MigrateDestinationUser::getKeySchema()
),
MigrateDestinationUser::getKeySchema()
);
// One good way to organize your mappings in the constructor is in three
@@ -239,7 +259,7 @@ class BeerUserMigration extends BasicExampleMigration {
// 'test_1'.
// dedupe() takes the Drupal table and column for determining uniqueness.
$this->addFieldMapping('name', 'name')
->dedupe('users', 'name');
->dedupe('users', 'name');
// The migrate module automatically converts date/time strings to UNIX
// timestamps.
@@ -252,7 +272,7 @@ class BeerUserMigration extends BasicExampleMigration {
// value is provided in addition to a source field, the default value will
// be applied to any rows where the source field is empty or NULL.
$this->addFieldMapping('roles')
->defaultValue(DRUPAL_AUTHENTICATED_RID);
->defaultValue(DRUPAL_AUTHENTICATED_RID);
$this->addFieldMapping('field_migrate_example_gender', 'sex');
@@ -262,16 +282,16 @@ class BeerUserMigration extends BasicExampleMigration {
// user.
if (module_exists('node_reference')) {
$this->addFieldMapping('field_migrate_example_favbeers', 'beers')
->separator('|');
->separator('|');
}
else {
$this->addFieldMapping(NULL, 'beers')
->issueGroup(t('DNM'));
->issueGroup(t('DNM'));
}
// Unmapped source fields
$this->addFieldMapping(NULL, 'nickname')
->issueGroup(t('DNM'));
->issueGroup(t('DNM'));
// Unmapped destination fields
@@ -297,15 +317,15 @@ class BeerUserMigration extends BasicExampleMigration {
// list of destination fields", and also lists "1 unmapped" under Destination,
// where it highlights "init" as unmapped.
$this->addFieldMapping('int')
->issueGroup(t('DNM'));
->issueGroup(t('DNM'));
$destination_fields = $this->destination->fields();
if (isset($destination_fields['path'])) {
$this->addFieldMapping('path')
->issueGroup(t('DNM'));
->issueGroup(t('DNM'));
if (isset($destination_fields['pathauto'])) {
$this->addFieldMapping('pathauto')
->issueGroup(t('DNM'));
->issueGroup(t('DNM'));
}
}
}
@@ -316,6 +336,7 @@ class BeerUserMigration extends BasicExampleMigration {
* and creates Drupal nodes of type 'Beer' as destination.
*/
class BeerNodeMigration extends BasicExampleMigration {
public function __construct($arguments) {
parent::__construct($arguments);
$this->description = t('Beers of the world');
@@ -326,9 +347,18 @@ class BeerNodeMigration extends BasicExampleMigration {
// each node? One way (valid for MySQL only) is to pull them into a single
// comma-separated list.
$query = db_select('migrate_example_beer_node', 'b')
->fields('b', array('bid', 'name', 'body', 'excerpt', 'aid',
'countries', 'image', 'image_alt', 'image_title',
'image_description'));
->fields('b', array(
'bid',
'name',
'body',
'excerpt',
'aid',
'countries',
'image',
'image_alt',
'image_title',
'image_description',
));
$query->leftJoin('migrate_example_beer_topic_node', 'tb', 'b.bid = tb.bid');
// Gives a single comma-separated list of related terms
$query->groupBy('tb.bid');
@@ -355,19 +385,19 @@ class BeerNodeMigration extends BasicExampleMigration {
'not null' => TRUE,
'description' => 'Beer ID.',
'alias' => 'b',
)
),
),
MigrateDestinationNode::getKeySchema()
);
// Mapped fields
$this->addFieldMapping('title', 'name')
->description(t('Mapping beer name in source to node title'));
->description(t('Mapping beer name in source to node title'));
$this->addFieldMapping('sticky')
->description(t('Should we default this to 0 or 1?'))
->issueGroup(t('Client questions'))
->issueNumber(765736)
->issuePriority(MigrateFieldMapping::ISSUE_PRIORITY_LOW);
->description(t('Should we default this to 0 or 1?'))
->issueGroup(t('Client questions'))
->issueNumber(765736)
->issuePriority(MigrateFieldMapping::ISSUE_PRIORITY_LOW);
// References to related objects (such as the author of the content) are
// most likely going to be identifiers from the source data, not Drupal
@@ -377,17 +407,17 @@ class BeerNodeMigration extends BasicExampleMigration {
// find a corresponding uid for the aid, the owner will be the administrative
// account.
$this->addFieldMapping('uid', 'aid')
// Note this is the machine name of the user migration.
->sourceMigration('BeerUser')
->defaultValue(1);
// Note this is the machine name of the user migration.
->sourceMigration('BeerUser')
->defaultValue(1);
// This is a multi-value text field - in the source data the values are
// separated by |, so we tell migrate to split it by that character.
$this->addFieldMapping('field_migrate_example_country', 'countries')
->separator('|');
->separator('|');
// These are related terms, which by default will be looked up by name.
$this->addFieldMapping('migrate_example_beer_styles', 'terms')
->separator(',');
->separator(',');
// Some fields may have subfields such as text formats or summaries. These
// can be individually mapped as we see here.
@@ -407,10 +437,10 @@ class BeerNodeMigration extends BasicExampleMigration {
// other options are available. In this case, MigrateFileUri indicates that
// the 'image' value is a URI.
$this->addFieldMapping('field_migrate_example_image:file_class')
->defaultValue('MigrateFileUri');
->defaultValue('MigrateFileUri');
// Here we specify the directory containing the source files.
$this->addFieldMapping('field_migrate_example_image:source_dir')
->defaultValue(drupal_get_path('module', 'migrate_example'));
->defaultValue(drupal_get_path('module', 'migrate_example'));
// And we map the alt and title values in the database to those on the image.
$this->addFieldMapping('field_migrate_example_image:alt', 'image_alt');
$this->addFieldMapping('field_migrate_example_image:title', 'image_title');
@@ -424,20 +454,20 @@ class BeerNodeMigration extends BasicExampleMigration {
// subfields of the same field may be grouped on the same line), and indent
// subfields to distinguish them from top-level fields.
$this->addUnmigratedDestinations(array(
'body:format',
'body:format',
'changed',
'comment',
'created',
'field_migrate_example_image:destination_dir',
'field_migrate_example_image:destination_file',
'field_migrate_example_image:file_replace',
'field_migrate_example_image:preserve_files',
'field_migrate_example_image:urlencode',
'field_migrate_example_image:destination_dir',
'field_migrate_example_image:destination_file',
'field_migrate_example_image:file_replace',
'field_migrate_example_image:preserve_files',
'field_migrate_example_image:urlencode',
'is_new',
'language',
'log',
'migrate_example_beer_styles:source_type',
'migrate_example_beer_styles:create_term',
'migrate_example_beer_styles:source_type',
'migrate_example_beer_styles:create_term',
'promote',
'revision',
'revision_uid',
@@ -448,10 +478,10 @@ class BeerNodeMigration extends BasicExampleMigration {
$destination_fields = $this->destination->fields();
if (isset($destination_fields['path'])) {
$this->addFieldMapping('path')
->issueGroup(t('DNM'));
->issueGroup(t('DNM'));
if (isset($destination_fields['pathauto'])) {
$this->addFieldMapping('pathauto')
->issueGroup(t('DNM'));
->issueGroup(t('DNM'));
}
}
if (module_exists('statistics')) {
@@ -466,14 +496,23 @@ class BeerNodeMigration extends BasicExampleMigration {
* Drupal comment objects.
*/
class BeerCommentMigration extends BasicExampleMigration {
public function __construct($arguments) {
parent::__construct($arguments);
$this->description = 'Comments about beers';
$query = db_select('migrate_example_beer_comment', 'mec')
->fields('mec', array('cid', 'cid_parent', 'name', 'mail', 'aid',
'body', 'bid', 'subject'))
->orderBy('cid_parent', 'ASC');
->fields('mec', array(
'cid',
'cid_parent',
'name',
'mail',
'aid',
'body',
'bid',
'subject',
))
->orderBy('cid_parent', 'ASC');
$this->source = new MigrateSourceSQL($query);
// Note that the machine name passed for comment migrations is
// 'comment_node_' followed by the machine name of the node type these
@@ -482,29 +521,30 @@ class BeerCommentMigration extends BasicExampleMigration {
new MigrateDestinationComment('comment_node_migrate_example_beer');
$this->map = new MigrateSQLMap($this->machineName,
array('cid' => array(
'type' => 'int',
'not null' => TRUE,
)
),
array(
'cid' => array(
'type' => 'int',
'not null' => TRUE,
),
),
MigrateDestinationComment::getKeySchema()
);
// Mapped fields
$this->addSimpleMappings(array('name', 'subject', 'mail'));
$this->addFieldMapping('status')
->defaultValue(COMMENT_PUBLISHED);
->defaultValue(COMMENT_PUBLISHED);
$this->addFieldMapping('nid', 'bid')
->sourceMigration('BeerNode');
->sourceMigration('BeerNode');
$this->addFieldMapping('uid', 'aid')
->sourceMigration('BeerUser')
->defaultValue(0);
->sourceMigration('BeerUser')
->defaultValue(0);
$this->addFieldMapping('pid', 'cid_parent')
->sourceMigration('BeerComment')
->description('Parent comment.');
->sourceMigration('BeerComment')
->description('Parent comment.');
$this->addFieldMapping('comment_body', 'body');
@@ -513,7 +553,7 @@ class BeerCommentMigration extends BasicExampleMigration {
// Unmapped destination fields
$this->addUnmigratedDestinations(array(
'changed',
'comment_body:format',
'comment_body:format',
'created',
'homepage',
'hostname',
@@ -524,10 +564,10 @@ class BeerCommentMigration extends BasicExampleMigration {
$destination_fields = $this->destination->fields();
if (isset($destination_fields['path'])) {
$this->addFieldMapping('path')
->issueGroup(t('DNM'));
->issueGroup(t('DNM'));
if (isset($destination_fields['pathauto'])) {
$this->addFieldMapping('pathauto')
->issueGroup(t('DNM'));
->issueGroup(t('DNM'));
}
}
}

View File

@@ -54,12 +54,12 @@ function migrate_example_beer_schema_node() {
return array(
'description' => 'Beers of the world.',
'fields' => array(
'bid' => array(
'bid' => array(
'type' => 'serial',
'not null' => TRUE,
'description' => 'Beer ID.',
),
'name' => array(
'name' => array(
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
@@ -120,7 +120,7 @@ function migrate_example_beer_schema_topic() {
return array(
'description' => 'Categories',
'fields' => array(
'style' => array(
'style' => array(
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
@@ -157,12 +157,12 @@ function migrate_example_beer_schema_topic_node() {
return array(
'description' => 'Beers topic pairs.',
'fields' => array(
'bid' => array(
'bid' => array(
'type' => 'int',
'not null' => TRUE,
'description' => 'Beer ID.',
),
'style' => array(
'style' => array(
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
@@ -177,12 +177,12 @@ function migrate_example_beer_schema_comment() {
return array(
'description' => 'Beers comments.',
'fields' => array(
'cid' => array(
'cid' => array(
'type' => 'serial',
'not null' => TRUE,
'description' => 'Comment ID.',
),
'bid' => array(
'bid' => array(
'type' => 'int',
'not null' => TRUE,
'description' => 'Beer ID that is being commented upon',
@@ -230,12 +230,12 @@ function migrate_example_beer_schema_account() {
return array(
'description' => 'Beers accounts.',
'fields' => array(
'aid' => array(
'aid' => array(
'type' => 'serial',
//'not null' => TRUE,
'not null' => TRUE,
'description' => 'Account ID',
),
'status' => array(
'status' => array(
'type' => 'int',
'not null' => TRUE,
'description' => 'Blocked_Allowed',
@@ -290,7 +290,7 @@ function migrate_example_beer_schema_legacy_urls() {
return array(
'description' => 'Stores legacy paths and destination ids for redirection.',
'fields' => array(
'id' => array(
'id' => array(
'type' => 'int',
'not null' => TRUE,
'description' => 'Primary Key: ID.',
@@ -475,8 +475,8 @@ function migrate_example_beer_image() {
function migrate_example_beer_favs() {
if (!field_info_field('field_migrate_example_favbeers')) {
$field = array(
'field_name' => 'field_migrate_example_favbeers',
'type' => 'node_reference',
'field_name' => 'field_migrate_example_favbeers',
'type' => 'node_reference',
'cardinality' => -1,
'settings' => array(
'referenceable_types' => array('migrate_example_beer'),
@@ -506,9 +506,10 @@ function migrate_example_beer_gender() {
'field_name' => 'field_migrate_example_gender',
'type' => 'list_integer',
'settings' => array(
'allowed_values' =>
"0|Male\n" .
"1|Female\n",
'allowed_values' => array(
0 => 'Male',
1 => 'Female'
),
),
);
field_create_field($field);
@@ -557,7 +558,11 @@ function migrate_example_beer_country() {
function migrate_example_beer_content_type_delete() {
$bundle = 'migrate_example_beer';
$field_names = array('migrate_example_beer_styles', 'field_migrate_example_image', 'field_migrate_example_country');
$field_names = array(
'migrate_example_beer_styles',
'field_migrate_example_image',
'field_migrate_example_country',
);
foreach ($field_names as $field_name) {
$instance = field_info_instance('node', $field_name, $bundle);
field_delete_instance($instance);
@@ -578,15 +583,58 @@ function migrate_example_beer_content_type_delete() {
}
function migrate_example_beer_data_node() {
$fields = array('bid', 'name', 'body', 'excerpt', 'countries', 'aid', 'image',
'image_alt', 'image_title', 'image_description');
$fields = array(
'bid',
'name',
'body',
'excerpt',
'countries',
'aid',
'image',
'image_alt',
'image_title',
'image_description',
);
$query = db_insert('migrate_example_beer_node')
->fields($fields);
->fields($fields);
// Use high bid numbers to avoid overwriting an existing node id.
$data = array(
array(99999999, 'Heineken', 'Blab Blah Blah Green', 'Green', 'Netherlands|Belgium', 0, 'heineken.jpg', 'Heinekin alt', 'Heinekin title', 'Heinekin description'), // comes with migrate_example project.
array(99999998, 'Miller Lite', 'We love Miller Brewing', 'Tasteless', 'USA|Canada', 1, NULL, NULL, NULL, NULL),
array(99999997, 'Boddington', 'English occassionally get something right', 'A treat', 'United Kingdom', 1, NULL, NULL, NULL, NULL),
array(
99999999,
'Heineken',
'Blab Blah Blah Green',
'Green',
'Netherlands|Belgium',
0,
'heineken.jpg',
'Heinekin alt',
'Heinekin title',
'Heinekin description',
), // comes with migrate_example project.
array(
99999998,
'Miller Lite',
'We love Miller Brewing',
'Tasteless',
'USA|Canada',
1,
NULL,
NULL,
NULL,
NULL,
),
array(
99999997,
'Boddington',
'English occassionally get something right',
'A treat',
'United Kingdom',
1,
NULL,
NULL,
NULL,
NULL,
),
);
foreach ($data as $row) {
$query->values(array_combine($fields, $row));
@@ -597,14 +645,59 @@ function migrate_example_beer_data_node() {
// Note that alice has duplicate username. Exercies dedupe() method.
// @TODO duplicate email also.
function migrate_example_beer_data_account() {
$fields = array('status', 'posted', 'name', 'nickname', 'password', 'mail', 'sex', 'beers');
$fields = array(
'status',
'posted',
'name',
'nickname',
'password',
'mail',
'sex',
'beers',
);
$query = db_insert('migrate_example_beer_account')
->fields($fields);
$data = array(
array(1, '2010-03-30 10:31:05', 'alice', 'alice hot pants', 'alicepass', 'alice@example.com', '1', '99999999|99999998|99999997'),
array(1, '2010-04-04 10:31:05', 'alice', 'alice dupe pants', 'alicepass', 'alice2@example.com', '1', '99999999|99999998|99999997'),
array(0, '2007-03-15 10:31:05', 'bob', 'rebob', 'bobpass', 'bob@example.com', '1', '99999999|99999997'),
array(1, '2004-02-29 10:31:05', 'charlie', 'charlie chocolate', 'mykids', 'charlie@example.com', '0', '99999999|99999998'),
array(
1,
'2010-03-30 10:31:05',
'alice',
'alice hot pants',
'alicepass',
'alice@example.com',
'1',
'99999999|99999998|99999997',
),
array(
1,
'2010-04-04 10:31:05',
'alice',
'alice dupe pants',
'alicepass',
'alice2@example.com',
'1',
'99999999|99999998|99999997',
),
array(
0,
'2007-03-15 10:31:05',
'bob',
'rebob',
'bobpass',
'bob@example.com',
'1',
'99999999|99999997',
),
array(
1,
'2004-02-29 10:31:05',
'charlie',
'charlie chocolate',
'mykids',
'charlie@example.com',
'0',
'99999999|99999998',
),
);
foreach ($data as $row) {
$query->values(array_combine($fields, $row));
@@ -613,15 +706,55 @@ function migrate_example_beer_data_account() {
}
function migrate_example_beer_data_comment() {
$fields = array('bid', 'cid_parent', 'subject', 'body', 'name', 'mail', 'aid');
$fields = array(
'bid',
'cid_parent',
'subject',
'body',
'name',
'mail',
'aid',
);
$query = db_insert('migrate_example_beer_comment')
->fields($fields);
$data = array(
array(99999998, NULL, 'im first', 'hot body', 'alice', 'alice@example.com', 0),
array(99999998, NULL, 'im second', 'hot body', 'alice', 'alice@example.com', 0),
array(99999999, NULL, 'im parent', 'hot body', 'alice', 'alice@example.com', 0),
array(
99999998,
NULL,
'im first',
'hot body',
'alice',
'alice@example.com',
0,
),
array(
99999998,
NULL,
'im second',
'hot body',
'alice',
'alice@example.com',
0,
),
array(
99999999,
NULL,
'im parent',
'hot body',
'alice',
'alice@example.com',
0,
),
array(99999999, 1, 'im child', 'cold body', 'bob', NULL, 1),
array(99999999, 2, 'im grandchild', 'bitter body', 'charlie@example.com', NULL, 1),
array(
99999999,
2,
'im grandchild',
'bitter body',
'charlie@example.com',
NULL,
1,
),
);
foreach ($data as $row) {
$query->values(array_combine($fields, $row));
@@ -636,7 +769,13 @@ function migrate_example_beer_data_topic() {
$data = array(
array('ale', 'traditional', NULL, 'Medieval British Isles', 'Medium'),
array('red ale', 'colorful', 'ale', NULL, NULL),
array('pilsner', 'refreshing', NULL, 'Pilsen, Bohemia (now Czech Republic)', 'Low'),
array(
'pilsner',
'refreshing',
NULL,
'Pilsen, Bohemia (now Czech Republic)',
'Low',
),
);
foreach ($data as $row) {
$query->values(array_combine($fields, $row));
@@ -660,13 +799,37 @@ function migrate_example_beer_data_topic_node() {
}
function migrate_example_beer_data_urls() {
$fields = array('id', 'migration_name', 'source_id', 'source_uri', 'modificationdatetime');
$fields = array(
'id',
'migration_name',
'source_id',
'source_uri',
'modificationdatetime',
);
$query = db_insert('migrate_example_beer_legacy_urls')
->fields($fields);
$data = array(
array(1, 'BeerNode', 99999997, 'the_boddington/main', strtotime('2010-04-12 08:32:06')),
array(2, 'BeerNode', 99999998, 'Miller Lite taste', strtotime('2010-04-12 08:32:05')),
array(3, 'BeerNode', 99999999, 'green wonder', strtotime('2010-04-12 08:32:03')),
array(
1,
'BeerNode',
99999997,
'the_boddington/main',
strtotime('2010-04-12 08:32:06'),
),
array(
2,
'BeerNode',
99999998,
'Miller Lite taste',
strtotime('2010-04-12 08:32:05'),
),
array(
3,
'BeerNode',
99999999,
'green wonder',
strtotime('2010-04-12 08:32:03'),
),
);
foreach ($data as $row) {
$query->values(array_combine($fields, $row));

View File

@@ -7,6 +7,7 @@
*/
class RoleTableMigration extends Migration {
public function __construct() {
parent::__construct();
$this->dependencies = array();
@@ -23,14 +24,15 @@ class RoleTableMigration extends Migration {
$this->destination = new MigrateDestinationTableCopy('role_copy', $destination_key);
$this->map = new MigrateSQLMap($this->machineName,
array('rid' => array(
array(
'rid' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'alias' => 'r',
)
),
$destination_key
),
),
$destination_key
);
}
}

View File

@@ -18,9 +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 2015-07-01
version = "7.x-2.8"
; Information added by Drupal.org packaging script on 2018-06-10
version = "7.x-2.11"
core = "7.x"
project = "migrate"
datestamp = "1435760949"
datestamp = "1528674486"

View File

@@ -63,8 +63,8 @@ function migrate_example_update_7001() {
);
$result = db_select('migrate_example_beer_legacy_urls', 'ms')
->fields('ms', array('machine_name', 'modificationdate'))
->execute();
->fields('ms', array('machine_name', 'modificationdate'))
->execute();
foreach ($result as $row) {
$modificationdatetime = strtotime($row->modificationdate);
db_update('migrate_example_beer_legacy_urls')
@@ -85,24 +85,24 @@ function migrate_example_update_7001() {
function migrate_example_update_7002() {
$ret = array();
db_add_field('migrate_example_beer_node', 'image_alt', array(
'type' => 'varchar',
'length' => 255,
'not null' => FALSE,
'description' => 'Image ALT',
'type' => 'varchar',
'length' => 255,
'not null' => FALSE,
'description' => 'Image ALT',
)
);
db_add_field('migrate_example_beer_node', 'image_title', array(
'type' => 'varchar',
'length' => 255,
'not null' => FALSE,
'description' => 'Image title',
'type' => 'varchar',
'length' => 255,
'not null' => FALSE,
'description' => 'Image title',
)
);
db_add_field('migrate_example_beer_node', 'image_description', array(
'type' => 'varchar',
'length' => 255,
'not null' => FALSE,
'description' => 'Image description',
'type' => 'varchar',
'length' => 255,
'not null' => FALSE,
'description' => 'Image description',
)
);
db_update('migrate_example_beer_node')
@@ -207,10 +207,10 @@ function migrate_example_update_7006() {
function migrate_example_update_7007() {
$ret = array();
db_add_field('migrate_example_wine_account', 'positions', array(
'type' => 'varchar',
'length' => 255,
'not null' => FALSE,
'description' => 'Positions held',
'type' => 'varchar',
'length' => 255,
'not null' => FALSE,
'description' => 'Positions held',
)
);
$query = db_update('migrate_example_wine_account')

View File

@@ -11,9 +11,8 @@ name = "Migrate example - Oracle"
package = "Migration"
project = "migrate_example_oracle"
; Information added by Drupal.org packaging script on 2015-07-01
version = "7.x-2.8"
; Information added by Drupal.org packaging script on 2018-06-10
version = "7.x-2.11"
core = "7.x"
project = "migrate"
datestamp = "1435760949"
datestamp = "1528674486"

View File

@@ -123,7 +123,7 @@ function migrate_example_oracle_requirements($phase) {
}
$sample_setting =
'<pre>
'<pre>
$conf[\'oracle_db\'] = array(
\'username\' => \'Oracle_username\',
\'password\' => \'Oracle_password\',
@@ -134,7 +134,7 @@ $conf[\'oracle_db\'] = array(
$requirements['oracle_db'] = array('title' => $t('Oracle configuration'));
global $conf;
if (empty($conf['oracle_db']) || empty($conf['oracle_db']['username']) ||
empty($conf['oracle_db']['password']) || empty($conf['oracle_db']['connection_string'])) {
empty($conf['oracle_db']['password']) || empty($conf['oracle_db']['connection_string'])) {
$requirements['oracle_db']['description'] = $t('You must define $conf[\'oracle_db\']
(in your site\'s settings.php file) to point to the Oracle database where
you want test data to be stored: ' . $sample_setting);
@@ -150,8 +150,10 @@ $conf[\'oracle_db\'] = array(
$e = oci_error();
$requirements['oracle_connect']['description'] = $t('Could not connect to configured
Oracle database at !conn_string. Oracle error message: !message',
array('!conn_string' => $conf['oracle_db']['connection_string'],
'!message' => $e['message']));
array(
'!conn_string' => $conf['oracle_db']['connection_string'],
'!message' => $e['message'],
));
$requirements['oracle_connect']['severity'] = REQUIREMENT_ERROR;
break;
}
@@ -159,35 +161,35 @@ $conf[\'oracle_db\'] = array(
// Check for necessary privileges
$requirements['oracle_privs'] = array('title' => $t('Necessary Oracle privileges are assigned'));
$statement = oci_parse($connection, 'SELECT * FROM SESSION_PRIVS');
if (!$statement) {
$e = oci_error($connection);
$requirements['oracle_connect']['description'] = $e['message'];
$requirements['oracle_connect']['severity'] = REQUIREMENT_ERROR;
if (!$statement) {
$e = oci_error($connection);
$requirements['oracle_connect']['description'] = $e['message'];
$requirements['oracle_connect']['severity'] = REQUIREMENT_ERROR;
break;
}
$result = oci_execute($statement);
if (!$result) {
$e = oci_error($statement);
$requirements['oracle_connect']['description'] = $e['message'];
$requirements['oracle_connect']['severity'] = REQUIREMENT_ERROR;
break;
}
$ok = FALSE;
while ($row = oci_fetch_object($statement)) {
if ($row->PRIVILEGE == 'CREATE TABLE') {
$ok = TRUE;
break;
}
$result = oci_execute($statement);
if (!$result) {
$e = oci_error($statement);
$requirements['oracle_connect']['description'] = $e['message'];
$requirements['oracle_connect']['severity'] = REQUIREMENT_ERROR;
break;
}
$ok = FALSE;
while ($row = oci_fetch_object($statement)) {
if ($row->PRIVILEGE == 'CREATE TABLE') {
$ok = TRUE;
break;
}
}
}
if (!$ok) {
$requirements['oracle_privs']['description'] = $t('The specified
if (!$ok) {
$requirements['oracle_privs']['description'] = $t('The specified
username !username does not have the CREATE TABLE privilege. This privilege
is necessary to create test tables in the Oracle database.',
array('!username' => $conf['oracle_db']['username']));
$requirements['oracle_privs']['severity'] = REQUIREMENT_ERROR;
break;
}
array('!username' => $conf['oracle_db']['username']));
$requirements['oracle_privs']['severity'] = REQUIREMENT_ERROR;
break;
}
break;
case 'update':
break;

View File

@@ -1,9 +1,10 @@
<?php
/**
* @file
* Examples and test fodder for migration from Oracle sources. To use this example
* (and to run the corresponding tests) you must define a connection to an Oracle database
* in your settings.php. E.g.,
* Examples and test fodder for migration from Oracle sources. To use this
* example
* (and to run the corresponding tests) you must define a connection to an
* Oracle database in your settings.php. E.g.,
*
* $conf['oracle_db'] = array(
* 'username' => 'DRUPAL',
@@ -11,17 +12,18 @@
* 'connection_string' => '//oracledb/orcl',
* );
*
* The username must have the CREATE TABLE privilege, so test data can be stored for the
* example to import.
* The username must have the CREATE TABLE privilege, so test data can be
* stored for the example to import.
*
* See http://us.php.net/manual/en/function.oci-connect.php for more information on
* connection_string.
* See http://us.php.net/manual/en/function.oci-connect.php for more
* information on connection_string.
*/
/**
* Migration class to test importing from Oracle into nodes.
*/
class MigrateExampleOracleNode extends Migration {
public function __construct() {
parent::__construct();
$this->description = t('Example migration from Oracle into nodes.');
@@ -35,7 +37,7 @@ class MigrateExampleOracleNode extends Migration {
'unsigned' => TRUE,
'not null' => TRUE,
'description' => 'Content ID',
)
),
),
MigrateDestinationNode::getKeySchema()
);
@@ -67,23 +69,31 @@ class MigrateExampleOracleNode extends Migration {
// Basic fields
$this->addFieldMapping('title', 'TITLE');
$this->addFieldMapping('uid')
->defaultValue(1);
->defaultValue(1);
$this->addFieldMapping('body', 'BODY');
$this->addFieldMapping('field_mainimage', 'MAINIMAGE')
->description('An image blob in the DB')
->arguments(array(
'file_function' => 'file_blob',
// Alternatively, specify a column here for dynamic file name.
'source_path' => 'druplicon.png',
->description('An image blob in the DB')
->arguments(array(
'file_function' => 'file_blob',
// Alternatively, specify a column here for dynamic file name.
'source_path' => 'druplicon.png',
));
));
$this->addFieldMapping('created', 'CREATED');
$this->addFieldMapping('changed', 'UPDATED');
// Unmapped destination fields
$this->addUnmigratedDestinations(array('is_new', 'status', 'promote',
'revision', 'language', 'sticky', 'revision_uid', 'path'));
$this->addUnmigratedDestinations(array(
'is_new',
'status',
'promote',
'revision',
'language',
'sticky',
'revision_uid',
'path',
));
}
}
@@ -95,7 +105,7 @@ function migrate_example_oracle_migrate_api() {
'api' => 2,
'migrations' => array(
'MigrateExampleOracle' => array('class_name' => 'MigrateExampleOracleNode'),
)
),
);
return $api;
}

View File

@@ -20,20 +20,36 @@ function migrate_example_oracle_generate($length) {
}
/**
* Return an array of data rows for testing Oracle import. Note that 4000 is a magic
* number for Oracle LOB datatypes, so we testing lengths above and below that limit.
* Return an array of data rows for testing Oracle import. Note that 4000 is a
* magic number for Oracle LOB datatypes, so we testing lengths above and below
* that limit.
*/
function migrate_example_oracle_sample_data() {
$image = file_get_contents('misc/druplicon.png');
return array(
array('oid' => 3, 'title' => 'Sample title', 'body' => 'Sample body',
'mainimage' => $image, 'created' => '2011/05/01 01:02:03',
'updated' => '2011/06/30 04:05:06'),
array('oid' => 5, 'title' => 'Another title', 'body' => migrate_example_oracle_generate(3900),
'mainimage' => $image, 'created' => '2011/08/12 07:08:09',
'updated' => '2011/12/25 10:11:12'),
array('oid' => 7, 'title' => 'Yet another title', 'body' => migrate_example_oracle_generate(4500),
'mainimage' => $image, 'created' => '2012/01/01 13:14:15',
'updated' => '2012/03/14 16:17:18'),
array(
'oid' => 3,
'title' => 'Sample title',
'body' => 'Sample body',
'mainimage' => $image,
'created' => '2011/05/01 01:02:03',
'updated' => '2011/06/30 04:05:06',
),
array(
'oid' => 5,
'title' => 'Another title',
'body' => migrate_example_oracle_generate(3900),
'mainimage' => $image,
'created' => '2011/08/12 07:08:09',
'updated' => '2011/12/25 10:11:12',
),
array(
'oid' => 7,
'title' => 'Yet another title',
'body' => migrate_example_oracle_generate(4500),
'mainimage' => $image,
'created' => '2012/01/01 13:14:15',
'updated' => '2012/03/14 16:17:18',
),
);
}

View File

@@ -72,13 +72,13 @@ function migrate_example_wine_schema_wine() {
return array(
'description' => 'Wines of the world',
'fields' => array(
'wineid' => array(
'wineid' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'description' => 'Wine ID',
),
'name' => array(
'name' => array(
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
@@ -140,7 +140,7 @@ function migrate_example_wine_schema_updates() {
return array(
'description' => 'Updated wine ratings',
'fields' => array(
'wineid' => array(
'wineid' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
@@ -161,13 +161,13 @@ function migrate_example_wine_schema_producer() {
return array(
'description' => 'Wine producers of the world',
'fields' => array(
'producerid' => array(
'producerid' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'description' => 'Producer ID',
),
'name' => array(
'name' => array(
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
@@ -211,7 +211,7 @@ function migrate_example_wine_schema_categories() {
'not null' => TRUE,
'description' => 'Type of category: variety, region, best_with',
),
'name' => array(
'name' => array(
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
@@ -242,12 +242,12 @@ function migrate_example_wine_schema_vintages() {
return array(
'description' => 'Wine vintages',
'fields' => array(
'wineid' => array(
'wineid' => array(
'type' => 'int',
'not null' => TRUE,
'description' => 'Wine ID',
),
'vintage' => array(
'vintage' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
@@ -282,12 +282,12 @@ function migrate_example_wine_schema_category_wine() {
return array(
'description' => 'Wine category assignments',
'fields' => array(
'wineid' => array(
'wineid' => array(
'type' => 'int',
'not null' => TRUE,
'description' => 'Wine ID',
),
'categoryid' => array(
'categoryid' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
@@ -302,12 +302,12 @@ function migrate_example_wine_schema_category_producer() {
return array(
'description' => 'Producer category assignments',
'fields' => array(
'producerid' => array(
'producerid' => array(
'type' => 'int',
'not null' => TRUE,
'description' => 'Producer ID',
),
'categoryid' => array(
'categoryid' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
@@ -322,13 +322,13 @@ function migrate_example_wine_schema_comment() {
return array(
'description' => 'Wine comments',
'fields' => array(
'commentid' => array(
'commentid' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'description' => 'Comment ID',
),
'wineid' => array(
'wineid' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
@@ -403,7 +403,7 @@ function migrate_example_wine_schema_comment_updates() {
return array(
'description' => 'Wine comment updates',
'fields' => array(
'commentid' => array(
'commentid' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
@@ -424,12 +424,12 @@ function migrate_example_wine_schema_account() {
return array(
'description' => 'Wine accounts.',
'fields' => array(
'accountid' => array(
'accountid' => array(
'type' => 'serial',
'not null' => TRUE,
'description' => 'Account ID',
),
'status' => array(
'status' => array(
'type' => 'int',
'not null' => TRUE,
'description' => 'Blocked_Allowed',
@@ -488,7 +488,7 @@ function migrate_example_wine_schema_account() {
'not null' => TRUE,
'description' => 'Signature for comments',
),
'imageid' => array(
'imageid' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => FALSE,
@@ -509,7 +509,7 @@ function migrate_example_wine_schema_account_updates() {
return array(
'description' => 'Wine account updates',
'fields' => array(
'accountid' => array(
'accountid' => array(
'type' => 'serial',
'not null' => TRUE,
'description' => 'Account ID',
@@ -529,7 +529,7 @@ function migrate_example_wine_schema_blobs() {
return array(
'description' => 'Wine blobs to be migrated to file entities',
'fields' => array(
'imageid' => array(
'imageid' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
@@ -549,31 +549,31 @@ function migrate_example_wine_schema_files() {
return array(
'description' => 'Wine and account files',
'fields' => array(
'imageid' => array(
'imageid' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'description' => 'Image ID',
),
'url' => array(
'url' => array(
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'description' => 'Image URL',
),
'image_alt' => array(
'image_alt' => array(
'type' => 'varchar',
'length' => 255,
'not null' => FALSE,
'description' => 'Image alt',
),
'image_title' => array(
'image_title' => array(
'type' => 'varchar',
'length' => 255,
'not null' => FALSE,
'description' => 'Image title',
),
'wineid' => array(
'wineid' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => FALSE,
@@ -588,19 +588,19 @@ function migrate_example_wine_schema_table_source() {
return array(
'description' => 'Source data to go into a custom Drupal table',
'fields' => array(
'fooid' => array(
'fooid' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'description' => 'Primary key',
),
'field1' => array(
'field1' => array(
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'description' => 'First field',
),
'field2' => array(
'field2' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
@@ -615,19 +615,19 @@ function migrate_example_wine_schema_table_dest() {
return array(
'description' => 'Custom Drupal table to receive source data directly',
'fields' => array(
'recordid' => array(
'recordid' => array(
'type' => 'serial',
'unsigned' => TRUE,
'not null' => TRUE,
'description' => 'Primary key',
),
'drupal_text' => array(
'drupal_text' => array(
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'description' => 'First field',
),
'drupal_int' => array(
'drupal_int' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
@@ -944,9 +944,12 @@ function migrate_example_wine_fields() {
function migrate_example_wine_content_type_delete() {
$bundle = 'migrate_example_wine';
$field_names = array('migrate_example_wine_varieties',
'migrate_example_wine_regions', 'migrate_example_wine_best_with',
'field_migrate_example_image');
$field_names = array(
'migrate_example_wine_varieties',
'migrate_example_wine_regions',
'migrate_example_wine_best_with',
'field_migrate_example_image',
);
foreach ($field_names as $field_name) {
$instance = field_info_instance('node', $field_name, $bundle);
field_delete_instance($instance);
@@ -964,15 +967,45 @@ function migrate_example_wine_content_type_delete() {
}
function migrate_example_wine_data_wine() {
$fields = array('wineid', 'name', 'body', 'excerpt', 'accountid',
'posted', 'last_changed', 'variety', 'region', 'rating');
$fields = array(
'wineid',
'name',
'body',
'excerpt',
'accountid',
'posted',
'last_changed',
'variety',
'region',
'rating',
);
$query = db_insert('migrate_example_wine')
->fields($fields);
->fields($fields);
$data = array(
array(1, 'Montes Classic Cabernet Sauvignon', 'Intense ruby-red color', 'Great!', 9,
strtotime('2010-01-02 03:04:05'), strtotime('2010-03-04 05:06:07'), 25, 17, 95),
array(2, 'Archeo Ruggero di Tasso Nero d\'Avola', 'Lots of berry character', 'Pair with red sauced dishes', 3,
strtotime('2010-09-03 18:23:58'), strtotime('2010-09-03 18:23:58'), 26, 2, 85),
array(
1,
'Montes Classic Cabernet Sauvignon',
'Intense ruby-red color',
'Great!',
9,
strtotime('2010-01-02 03:04:05'),
strtotime('2010-03-04 05:06:07'),
25,
17,
95,
),
array(
2,
'Archeo Ruggero di Tasso Nero d\'Avola',
'Lots of berry character',
'Pair with red sauced dishes',
3,
strtotime('2010-09-03 18:23:58'),
strtotime('2010-09-03 18:23:58'),
26,
2,
85,
),
);
foreach ($data as $row) {
$query->values(array_combine($fields, $row));
@@ -983,7 +1016,7 @@ function migrate_example_wine_data_wine() {
function migrate_example_wine_data_updates() {
$fields = array('wineid', 'rating');
$query = db_insert('migrate_example_wine_updates')
->fields($fields);
->fields($fields);
$data = array(
array(1, 93),
array(2, NULL),
@@ -997,7 +1030,7 @@ function migrate_example_wine_data_updates() {
function migrate_example_wine_data_producer() {
$fields = array('producerid', 'name', 'body', 'excerpt', 'accountid');
$query = db_insert('migrate_example_wine_producer')
->fields($fields);
->fields($fields);
$data = array(
array(1, 'Montes', 'Fine Chilean winery', 'Great!', 9),
array(2, 'Archeo', 'Sicilia!', NULL, 3),
@@ -1009,20 +1042,69 @@ function migrate_example_wine_data_producer() {
}
function migrate_example_wine_data_account() {
$fields = array('accountid', 'status', 'posted', 'last_access', 'last_login',
'name', 'sex', 'password', 'mail', 'original_mail', 'sig', 'imageid', 'positions');
$fields = array(
'accountid',
'status',
'posted',
'last_access',
'last_login',
'name',
'sex',
'password',
'mail',
'original_mail',
'sig',
'imageid',
'positions',
);
$query = db_insert('migrate_example_wine_account')
->fields($fields);
$data = array(
array(1, 1, '2010-03-30 10:31:05', '2010-04-30 18:25:24', '2010-04-30 14:01:02',
'darren', 'M', 'dpass', 'ddarren@example.com', 'darren@example.com',
'All about the Australians', NULL, '5'),
array(3, 0, '2007-03-15 10:31:05', '2007-06-10 04:11:38', '2007-06-10 04:11:38',
'emily', 'F', 'insecure', 'emily@example.com', 'emily@example.com',
'Sommelier to the stars', NULL, '18'),
array(9, 1, '2004-02-29 10:31:05', '2004-02-29 10:31:05', '2004-02-29 10:31:05',
'fonzie', NULL, 'bike', 'thefonz@example.com', 'arthur@example.com',
'Aaay!', 1, '5,18'),
array(
1,
1,
'2010-03-30 10:31:05',
'2010-04-30 18:25:24',
'2010-04-30 14:01:02',
'darren',
'M',
'dpass',
'ddarren@example.com',
'darren@example.com',
'All about the Australians',
NULL,
'5',
),
array(
3,
0,
'2007-03-15 10:31:05',
'2007-06-10 04:11:38',
'2007-06-10 04:11:38',
'emily',
'F',
'insecure',
'emily@example.com',
'emily@example.com',
'Sommelier to the stars',
NULL,
'18',
),
array(
9,
1,
'2004-02-29 10:31:05',
'2004-02-29 10:31:05',
'2004-02-29 10:31:05',
'fonzie',
NULL,
'bike',
'thefonz@example.com',
'arthur@example.com',
'Aaay!',
1,
'5,18',
),
);
foreach ($data as $row) {
$query->values(array_combine($fields, $row));
@@ -1033,7 +1115,7 @@ function migrate_example_wine_data_account() {
function migrate_example_wine_data_account_updates() {
$fields = array('accountid', 'sex');
$query = db_insert('migrate_example_wine_account_updates')
->fields($fields);
->fields($fields);
$data = array(
array(1, NULL),
array(3, 'M'),
@@ -1046,26 +1128,93 @@ function migrate_example_wine_data_account_updates() {
}
function migrate_example_wine_data_comment() {
$fields = array('commentid', 'wineid', 'comment_parent', 'subject', 'body',
'name', 'mail', 'accountid', 'commenthost', 'userpage', 'posted', 'lastchanged');
$fields = array(
'commentid',
'wineid',
'comment_parent',
'subject',
'body',
'name',
'mail',
'accountid',
'commenthost',
'userpage',
'posted',
'lastchanged',
);
$query = db_insert('migrate_example_wine_comment')
->fields($fields);
$data = array(
array(1, 1, NULL, 'im first', 'Tasty', 'grace', 'grace@example.com', 0,
'123.456.78.9', 'http:://grace.example.com/',
strtotime('2010-01-02 03:04:05'), strtotime('2010-04-05 06:07:08')),
array(2, 1, NULL, 'im second', 'Delicious', 'horace', 'horace@example.com', 0,
'example.com', NULL,
strtotime('2010-02-02 03:04:05'), strtotime('2010-05-05 06:07:08')),
array(3, 1, NULL, 'im parent', 'Don\'t care for it', 'irene', 'irene@example.com', 0,
'254.0.2.5', 'http:://www.example.com/irene',
strtotime('2010-03-02 03:04:05'), strtotime('2010-03-02 03:04:05')),
array(4, 1, 3, 'im child', 'But it\'s so good!', 'emily', NULL, 3,
'58.29.126.1', 'http:://www.wine.com/',
strtotime('2010-01-02 03:04:05'), strtotime('2010-01-02 03:04:05')),
array(5, 1, 4, 'im grandchild', 'Right on, Emily!', 'thefonz@example.com', NULL, 9,
'123.456.78.9', NULL,
strtotime('2010-06-02 03:04:05'), strtotime('2010-06-02 03:04:05')),
array(
1,
1,
NULL,
'im first',
'Tasty',
'grace',
'grace@example.com',
0,
'123.456.78.9',
'http:://grace.example.com/',
strtotime('2010-01-02 03:04:05'),
strtotime('2010-04-05 06:07:08'),
),
array(
2,
1,
NULL,
'im second',
'Delicious',
'horace',
'horace@example.com',
0,
'example.com',
NULL,
strtotime('2010-02-02 03:04:05'),
strtotime('2010-05-05 06:07:08'),
),
array(
3,
1,
NULL,
'im parent',
'Don\'t care for it',
'irene',
'irene@example.com',
0,
'254.0.2.5',
'http:://www.example.com/irene',
strtotime('2010-03-02 03:04:05'),
strtotime('2010-03-02 03:04:05'),
),
array(
4,
1,
3,
'im child',
'But it\'s so good!',
'emily',
NULL,
3,
'58.29.126.1',
'http:://www.wine.com/',
strtotime('2010-01-02 03:04:05'),
strtotime('2010-01-02 03:04:05'),
),
array(
5,
1,
4,
'im grandchild',
'Right on, Emily!',
'thefonz@example.com',
NULL,
9,
'123.456.78.9',
NULL,
strtotime('2010-06-02 03:04:05'),
strtotime('2010-06-02 03:04:05'),
),
);
foreach ($data as $row) {
$query->values(array_combine($fields, $row));
@@ -1076,7 +1225,7 @@ function migrate_example_wine_data_comment() {
function migrate_example_wine_data_comment_updates() {
$fields = array('commentid', 'subject');
$query = db_insert('migrate_example_wine_comment_updates')
->fields($fields);
->fields($fields);
$data = array(
array(1, 'I am first'),
array(2, 'I am second'),
@@ -1091,12 +1240,33 @@ function migrate_example_wine_data_comment_updates() {
}
function migrate_example_wine_data_categories() {
$fields = array('categoryid', 'type', 'name', 'category_parent', 'details', 'ordering');
$fields = array(
'categoryid',
'type',
'name',
'category_parent',
'details',
'ordering',
);
$query = db_insert('migrate_example_wine_categories')
->fields($fields);
->fields($fields);
$data = array(
array(1, 'variety', 'White wine', NULL, 'White wines are generally simpler and sweeter than red', 3),
array(3, 'variety', 'Red wine', NULL, 'Red wines are generally more complex and "dry" than white', 1),
array(
1,
'variety',
'White wine',
NULL,
'White wines are generally simpler and sweeter than red',
3,
),
array(
3,
'variety',
'Red wine',
NULL,
'Red wines are generally more complex and "dry" than white',
1,
),
array(8, 'variety', 'Riesling', 1, 'Associated with Germany', 2),
array(9, 'variety', 'Chardonnay', 1, 'One of the most popular whites', 1),
array(13, 'variety', 'Merlot', 3, 'Very drinkable', 4),
@@ -1128,7 +1298,7 @@ function migrate_example_wine_data_categories() {
function migrate_example_wine_data_vintages() {
$fields = array('wineid', 'vintage');
$query = db_insert('migrate_example_wine_vintages')
->fields($fields);
->fields($fields);
$data = array(
array(1, 2006),
array(1, 2007),
@@ -1143,7 +1313,7 @@ function migrate_example_wine_data_vintages() {
function migrate_example_wine_data_variety_updates() {
$fields = array('categoryid', 'details');
$query = db_insert('migrate_example_wine_variety_updates')
->fields($fields);
->fields($fields);
$data = array(
array(1, 'White wines are simpler and sweeter than red'),
array(3, 'Red wines are generally more complex and dry than white'),
@@ -1194,9 +1364,27 @@ function migrate_example_wine_data_files() {
->fields($fields);
$data = array(
array(1, 'http://placekitten.com/200/200', NULL, NULL, NULL),
array(2, 'http://cyrve.com/files/penguin.jpeg', 'Penguin alt', 'Penguin title', 1),
array(3, 'http://cyrve.com/files/rioja.jpeg', 'Rioja alt', 'Rioja title', 2),
array(4, 'http://cyrve.com/files/boutisse_0.jpeg', 'Boutisse alt', 'Boutisse title', 2),
array(
2,
'http://cyrve.com/files/penguin.jpeg',
'Penguin alt',
'Penguin title',
1,
),
array(
3,
'http://cyrve.com/files/rioja.jpeg',
'Rioja alt',
'Rioja title',
2,
),
array(
4,
'http://cyrve.com/files/boutisse_0.jpeg',
'Boutisse alt',
'Boutisse title',
2,
),
);
foreach ($data as $row) {
$query->values(array_combine($fields, $row));

View File

@@ -24,9 +24,8 @@ name = "migrate_example_baseball"
package = "Migration"
php = "5.2.4"
; Information added by Drupal.org packaging script on 2015-07-01
version = "7.x-2.8"
; Information added by Drupal.org packaging script on 2018-06-10
version = "7.x-2.11"
core = "7.x"
project = "migrate"
datestamp = "1435760949"
datestamp = "1528674486"

View File

@@ -8,7 +8,7 @@
function migrate_example_baseball_enable() {
$path = dirname(__FILE__) . '/data';
migrate_example_baseball_get_files($path);
for ($i=0; $i<=9; $i++) {
for ($i = 0; $i <= 9; $i++) {
$file = 'GL200' . $i . '.TXT';
Migration::registerMigration('GameBaseball',
pathinfo($file, PATHINFO_FILENAME),
@@ -26,7 +26,7 @@ function migrate_example_baseball_get_files($path) {
if (!file_exists("$path/GL2000.TXT") && !file_exists("$path/gl2000.txt")) {
file_prepare_directory($path, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
$result = copy('http://www.retrosheet.org/gamelogs/gl2000_09.zip',
$path . '/gl2000_09.zip');
$path . '/gl2000_09.zip');
if ($result) {
$zip = new ZipArchive();
$zip->open($path . '/gl2000_09.zip');
@@ -39,11 +39,22 @@ function migrate_example_baseball_get_files($path) {
function migrate_example_baseball_uninstall() {
$bundle = 'migrate_example_baseball';
$field_names = array('field_park', 'field_home_team', 'field_home_game_number',
'field_home_score', 'field_visiting_score', 'field_outs', 'field_attendance',
'field_duration', 'field_home_batters', 'field_visiting_batters',
'field_home_pitcher', 'field_visiting_pitcher', 'field_visiting_team',
'field_start_date');
$field_names = array(
'field_park',
'field_home_team',
'field_home_game_number',
'field_home_score',
'field_visiting_score',
'field_outs',
'field_attendance',
'field_duration',
'field_home_batters',
'field_visiting_batters',
'field_home_pitcher',
'field_visiting_pitcher',
'field_visiting_team',
'field_start_date',
);
foreach ($field_names as $field_name) {
$instance = field_info_instance('node', $field_name, $bundle);
field_delete_instance($instance);

View File

@@ -26,30 +26,34 @@ function migrate_example_baseball_migrate_api() {
* A migration that is reused for each source CSV file.
*/
class GameBaseball extends Migration {
public function __construct($arguments) {
parent::__construct($arguments);
$this->description = t('Import box scores from CSV file.');
// Create a map object for tracking the relationships between source rows
$this->map = new MigrateSQLMap($this->machineName,
array(
'start_date' => array('type' => 'varchar',
'length' => 8,
'not null' => TRUE,
'description' => 'Start date',
),
'home_team' => array('type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'description' => 'Home team',
),
'home_game_number' => array('type' => 'int',
'not null' => TRUE,
'description' => 'Home team game number',
),
array(
'start_date' => array(
'type' => 'varchar',
'length' => 8,
'not null' => TRUE,
'description' => 'Start date',
),
MigrateDestinationNode::getKeySchema()
);
'home_team' => array(
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'description' => 'Home team',
),
'home_game_number' => array(
'type' => 'int',
'not null' => TRUE,
'description' => 'Home team game number',
),
),
MigrateDestinationNode::getKeySchema()
);
// Create a MigrateSource object, which manages retrieving the input data.
$this->source = new MigrateSourceCSV($arguments['source_file'], $this->csvcolumns(), array(), $this->fields());
@@ -57,7 +61,7 @@ class GameBaseball extends Migration {
$this->destination = new MigrateDestinationNode('migrate_example_baseball');
$this->addFieldMapping('title', 'title')
->description('See prepareRow().');
->description('See prepareRow().');
$this->addFieldMapping('field_start_date', 'start_date');
$this->addFieldMapping('field_park', 'park_id');
$this->addFieldMapping('field_visiting_team', 'visiting_team');
@@ -68,20 +72,20 @@ class GameBaseball extends Migration {
$this->addFieldMapping('field_outs', 'outs');
$this->addFieldMapping('field_attendance', 'attendance');
$this->addFieldMapping('field_duration', 'duration')
->defaultValue(NULL);
->defaultValue(NULL);
$this->addFieldMapping('field_home_pitcher', 'home_pitcher');
$this->addFieldMapping('field_visiting_pitcher', 'visiting_pitcher');
$this->addFieldMapping('field_home_batters', 'home_batters')
->separator(',')
->description('See prepareRow().');
->separator(',')
->description('See prepareRow().');
$this->addFieldMapping('field_visiting_batters', 'visiting_batters')
->separator(',')
->description('See prepareRow().');
for ($i=1; $i <= 9; $i++ ) {
->separator(',')
->description('See prepareRow().');
for ($i = 1; $i <= 9; $i++) {
$this->addFieldMapping(NULL, "visiting_batter_$i")
->description('Not needed since we use the multi-value field: visiting_batters.');
->description('Not needed since we use the multi-value field: visiting_batters.');
$this->addFieldMapping(NULL, "home_batter_$i")
->description('Not needed since we use the multi-value field: home_batters.');
->description('Not needed since we use the multi-value field: home_batters.');
}
}
@@ -97,9 +101,12 @@ class GameBaseball extends Migration {
$columns[16] = array('park_id', 'Ballpark ID');
$columns[17] = array('attendance', 'Attendance');
$columns[18] = array('duration', 'Duration in minutes');
for ($i=1; $i <= 9; $i++ ) {
$columns[103+3*$i] = array("visiting_batter_$i", "Visiting batter $i");
$columns[130+3*$i] = array("home_batter_$i", "Home batter $i");
for ($i = 1; $i <= 9; $i++) {
$columns[103 + 3 * $i] = array(
"visiting_batter_$i",
"Visiting batter $i",
);
$columns[130 + 3 * $i] = array("home_batter_$i", "Home batter $i");
}
$columns[102] = array('visiting_pitcher', 'Visiting starting pitcher');
$columns[104] = array('home_pitcher', 'Home starting pitcher');
@@ -108,11 +115,11 @@ class GameBaseball extends Migration {
public function prepareRow($row) {
// Collect all the batters into one multi-value field.
for ($i=1; $i <= 9; $i++ ) {
for ($i = 1; $i <= 9; $i++) {
$key = "visiting_batter_$i";
$visiting_batters[] = $row->$key;
$visiting_batters[] = $row->{$key};
$key = "home_batter_$i";
$home_batters[] = $row->$key;
$home_batters[] = $row->{$key};
}
$row->visiting_batters = implode(',', $visiting_batters);
$row->home_batters = implode(',', $home_batters);
@@ -124,7 +131,7 @@ class GameBaseball extends Migration {
*/
protected function generateMachineName($class_name = NULL) {
return drupal_strtolower(pathinfo($this->arguments['source_file'],
PATHINFO_FILENAME));
PATHINFO_FILENAME));
}
public function fields() {

View File

@@ -1,18 +1,15 @@
table.migrate-dashboard tr.migrate-running {
background-color: #CFC;
background-color: #cfc;
}
.migrate-running {
background-color: #CFC;
background-color: #cfc;
}
.migrate-option-separator {
margin-bottom:0.2em;
margin-bottom: 0.2em;
padding-bottom: 0.2em;
border-bottom: 1px solid #aaa;
}
#migrate-migration-info td.migrate-error {
background: #ffc9c9;
}

View File

@@ -6,9 +6,8 @@ core = 7.x
dependencies[] = migrate
files[] = migrate_ui.wizard.inc
; Information added by Drupal.org packaging script on 2015-07-01
version = "7.x-2.8"
; Information added by Drupal.org packaging script on 2018-06-10
version = "7.x-2.11"
core = "7.x"
project = "migrate"
datestamp = "1435760949"
datestamp = "1528674486"

View File

@@ -35,10 +35,10 @@ function migrate_ui_update_7201() {
*/
function migrate_ui_set_weight() {
$node_weight = db_select('system', 's')
->fields('s', array('weight'))
->condition('name', 'node')
->execute()
->fetchField();
->fields('s', array('weight'))
->condition('name', 'node')
->execute()
->fetchField();
db_update('system')
->fields(array('weight' => $node_weight + 1))
->condition('name', 'migrate_ui')
@@ -62,10 +62,10 @@ function migrate_ui_update_7202() {
}
variable_set('migrate_import_method', $import_method);
variable_set('migrate_drush_mail',
variable_get('wordpress_migrate_notification', 0));
variable_get('wordpress_migrate_notification', 0));
variable_set('migrate_drush_mail_subject',
variable_get('wordpress_migrate_notification_subject', ''));
variable_get('wordpress_migrate_notification_subject', ''));
variable_set('migrate_drush_mail_body',
variable_get('wordpress_migrate_notification_body', ''));
variable_get('wordpress_migrate_notification_body', ''));
}
}

View File

@@ -123,10 +123,10 @@ function migrate_ui_migrate_migration_title($migration_name) {
}
/**
* Implements hook_theme()
*
* @return array
*/
* Implements hook_theme()
*
* @return array
*/
function migrate_ui_theme() {
return array(
'migrate_ui_field_mapping_form' => array(

View File

@@ -25,15 +25,15 @@ function migrate_ui_migrate_dashboard($form, &$form_state) {
);
$result = db_select('migrate_group', 'mg')
->fields('mg', array('name', 'title', 'arguments'))
->execute();
->fields('mg', array('name', 'title', 'arguments'))
->execute();
$rows = array();
foreach ($result as $group_row) {
$row = array();
$migration_result = db_select('migrate_status', 'ms')
->fields('ms', array('machine_name', 'status', 'arguments'))
->condition('group_name', $group_row->name)
->execute();
->fields('ms', array('machine_name', 'status', 'arguments'))
->condition('group_name', $group_row->name)
->execute();
if (!$migration_result) {
continue;
}
@@ -201,17 +201,8 @@ function migrate_ui_migrate_group($form, &$form_state, $group_name) {
$row['status'] = $status;
$machine_name = $migration->getMachineName();
$name_length = strlen($machine_name);
$group_length = strlen($group_name);
if ($name_length != $group_length &&
!strncasecmp($group_name, $machine_name, $group_length)) {
$display_name = substr($machine_name, $group_length);
}
else {
$display_name = $machine_name;
}
$row['machinename'] =
l($display_name, "admin/content/migrate/groups/$group_name/$machine_name");
l($machine_name, "admin/content/migrate/groups/$group_name/$machine_name");
$row['importrows'] = (int) $total;
$row['imported'] = (int) $imported;
$row['unprocessed'] = (int) $unprocessed;
@@ -287,7 +278,7 @@ function _migrate_ui_migrate_operations() {
'import_immediate' => t('Import'),
'rollback_immediate' => t('Rollback'),
);
break;
break;
}
$options += array(
@@ -460,10 +451,16 @@ function migrate_ui_migrate_submit($form, &$form_state) {
if ($update && method_exists($migration, 'prepareUpdate')) {
$migration->prepareUpdate();
}
$operations[] = array('migrate_ui_batch', array('import', $machine_name, $limit, $force));
$operations[] = array(
'migrate_ui_batch',
array('import', $machine_name, $limit, $force),
);
break;
case 'rollback_immediate':
$operations[] = array('migrate_ui_batch', array('rollback', $machine_name, $limit, $force));
$operations[] = array(
'migrate_ui_batch',
array('rollback', $machine_name, $limit, $force),
);
break;
case 'import_background':
case 'rollback_background':
@@ -543,7 +540,7 @@ function migrate_ui_migrate_submit($form, &$form_state) {
drupal_set_message('Your operation is running in the background. You will receive an email message when it is complete.');
}
else {
drupal_set_message('Your operation is running in the background. You may '.
drupal_set_message('Your operation is running in the background. You may ' .
'refresh the dashboard page to check on its progress.');
}
}
@@ -590,10 +587,16 @@ function migrate_ui_batch($operation, $machine_name, $limit, $force = FALSE, &$c
// Perform the requested operation
switch ($operation) {
case 'import':
$result = $migration->processImport(array('limit' => $limit, 'force' => $force));
$result = $migration->processImport(array(
'limit' => $limit,
'force' => $force,
));
break;
case 'rollback':
$result = $migration->processRollback(array('limit' => $limit, 'force' => $force));
$result = $migration->processRollback(array(
'limit' => $limit,
'force' => $force,
));
break;
}
@@ -608,10 +611,10 @@ function migrate_ui_batch($operation, $machine_name, $limit, $force = FALSE, &$c
switch ($operation) {
case 'import':
$to_update = $migration->updateCount();
$context['finished'] = ($processed-$to_update)/$total;
$context['finished'] = ($processed - $to_update) / $total;
break;
case 'rollback':
$context['finished'] = ($total - $migration->importedCount())/$total;
$context['finished'] = ($total - $migration->importedCount()) / $total;
break;
}
}
@@ -623,8 +626,8 @@ function migrate_ui_batch($operation, $machine_name, $limit, $force = FALSE, &$c
array(
'!name' => $machine_name,
'!depends' => implode(", ", $migration->incompleteDependencies()),
))
);
)),
);
$context['finished'] = 1;
break;
case MigrationBase::RESULT_STOPPED:
@@ -770,7 +773,7 @@ function migrate_migration_info($form, $form_state, $group_name, $migration_name
$dependencies = $migration->getHardDependencies();
if (count($dependencies) > 0) {
$form['overview']['dependencies'] = array(
'#title' => t('Dependencies') ,
'#title' => t('Dependencies'),
'#markup' => filter_xss_admin(implode(', ', $dependencies)),
'#type' => 'item',
);
@@ -903,7 +906,13 @@ function migrate_migration_info($form, $form_state, $group_name, $migration_name
'#empty' => t('No fields'),
);
$header = array(t('Destination'), t('Source'), t('Default'), t('Description'), t('Priority'));
$header = array(
t('Destination'),
t('Source'),
t('Default'),
t('Description'),
t('Priority'),
);
// First group the mappings
$descriptions = array();
@@ -917,17 +926,18 @@ function migrate_migration_info($form, $form_state, $group_name, $migration_name
if (!is_null($source_field) && !isset($source_fields[$source_field])) {
drupal_set_message(t('"!source" was used as source field in the
"!destination" mapping but is not in list of source fields', array(
'!source' => filter_xss_admin($source_field),
'!destination' => filter_xss_admin($destination_field),
)),
'warning');
'!source' => filter_xss_admin($source_field),
'!destination' => filter_xss_admin($destination_field),
)),
'warning');
}
if (!is_null($destination_field) && !isset($destination_fields[$destination_field])) {
drupal_set_message(t('"!destination" was used as destination field in
"!source" mapping but is not in list of destination fields', array(
'!source' => filter_xss_admin($source_field),
'!destination' => filter_xss_admin($destination_field))),
'warning');
'!source' => filter_xss_admin($source_field),
'!destination' => filter_xss_admin($destination_field),
)),
'warning');
}
$descriptions[$mapping->getIssueGroup()][] = $mapping;
}
@@ -954,7 +964,7 @@ function migrate_migration_info($form, $form_state, $group_name, $migration_name
$issue_number = $mapping->getIssueNumber();
if (!is_null($issue_pattern) && !is_null($issue_number)) {
$priority .= ' (' . l(t('#') . $issue_number, str_replace(':id:', $issue_number,
$issue_pattern)) . ')';
$issue_pattern)) . ')';
}
if ($issue_priority != MigrateFieldMapping::ISSUE_PRIORITY_OK) {
$classes[] = 'migrate-error';
@@ -972,10 +982,16 @@ function migrate_migration_info($form, $form_state, $group_name, $migration_name
$source_field = "<em>$source_field</em>";
}
$row = array(
array('data' => filter_xss_admin($destination_field), 'class' => $classes),
array(
'data' => filter_xss_admin($destination_field),
'class' => $classes,
),
array('data' => filter_xss_admin($source_field), 'class' => $classes),
array('data' => filter_xss_admin($default), 'class' => $classes),
array('data' => filter_xss_admin($mapping->getDescription()), 'class' => $classes),
array(
'data' => filter_xss_admin($mapping->getDescription()),
'class' => $classes,
),
array('data' => filter_xss_admin($priority), 'class' => $classes),
);
$rows[] = $row;
@@ -1091,14 +1107,14 @@ function migrate_ui_edit_mappings($form, $form_state, $group_name,
// Check for a click of the DNM box...
if (isset($form_state['values']) &&
$form_state['values']['source_fields'][$name] == 1) {
$form_state['values']['source_fields'][$name] == 1) {
$dnm_value = 1;
}
else {
// ... or a source-only mapping with the DNM issue group.
foreach ($field_mappings as $mapping) {
if ($mapping->getSourceField() == $name &&
$mapping->getIssueGroup() == t('DNM')) {
$mapping->getIssueGroup() == t('DNM')) {
$dnm_value = 1;
}
}
@@ -1119,7 +1135,8 @@ function migrate_ui_edit_mappings($form, $form_state, $group_name,
if (isset($field_mappings['is_new'])) {
$default_is_new = $field_mappings['is_new']->getDefaultValue();
} else {
}
else {
$default_is_new = 0;
}
foreach ($dest_fields as $name => $description) {
@@ -1146,7 +1163,7 @@ function migrate_ui_edit_mappings($form, $form_state, $group_name,
// If the DNM box has been clicked, make sure we clear the mapping and
// default value fields.
if (isset($form_state['values']) &&
$form_state['values']['field_mappings'][$name]['issue_group'] == 1) {
$form_state['values']['field_mappings'][$name]['issue_group'] == 1) {
$dnm_value = 1;
}
else {
@@ -1185,7 +1202,7 @@ function migrate_ui_edit_mappings($form, $form_state, $group_name,
$form['field_mappings'][$name]['mapping'] = array(
'#type' => 'select',
'#title' => t($label,
array('!description' => $description, '!field_name' => $name)),
array('!description' => $description, '!field_name' => $name)),
'#options' => $options,
'#default_value' => $default_mapping,
);
@@ -1245,7 +1262,7 @@ function migrate_ui_edit_mappings($form, $form_state, $group_name,
// Remove any migrations depending on us, directly or indirectly. First, get
// a list of such migrations.
$descendent_migrations = _migrate_ui_get_descendents($migration_name,
$all_dependencies);
$all_dependencies);
$source_migration_options = array_diff_key($source_migration_options,
$descendent_migrations);
foreach ($source_migration_options as $machine_name) {
@@ -1294,7 +1311,7 @@ function _migrate_ui_get_descendents($migration_name, array $all_dependencies) {
if (in_array($migration_name, $dependencies)) {
$descendents[$machine_name] = $machine_name;
$descendents += _migrate_ui_get_descendents($machine_name,
$all_dependencies);
$all_dependencies);
}
}
return $descendents;
@@ -1310,10 +1327,10 @@ function _migrate_ui_get_descendents($migration_name, array $all_dependencies) {
function migrate_ui_edit_mappings_submit(&$form, &$form_state) {
$machine_name = $form_state['values']['machine_name'];
$row = db_select('migrate_status', 'ms')
->fields('ms', array('arguments', 'class_name', 'group_name'))
->condition('machine_name', $machine_name)
->execute()
->fetchObject();
->fields('ms', array('arguments', 'class_name', 'group_name'))
->condition('machine_name', $machine_name)
->execute()
->fetchObject();
$class_name = $row->class_name;
$group_name = $row->group_name;
$arguments = unserialize($row->arguments);
@@ -1359,17 +1376,17 @@ function migrate_ui_edit_mappings_submit(&$form, &$form_state) {
$info['source_migration'] = NULL;
}
if ($info['issue_group'] == 0 && $coded_mappings[$destination_field]->getIssueGroup() != t('DNM') ||
$info['issue_group'] == 1 && $coded_mappings[$destination_field]->getIssueGroup() == t('DNM')) {
$info['issue_group'] == 1 && $coded_mappings[$destination_field]->getIssueGroup() == t('DNM')) {
$dnm_matches = TRUE;
}
else {
$dnm_matches = FALSE;
}
if ($info['mapping'] == $coded_source_field &&
$info['default_value'] == $coded_default_value &&
$info['source_migration'] == $coded_source_migration &&
(!$xml || ($xml && ($info['xpath'] == $coded_xpath))) &&
$dnm_matches) {
$info['default_value'] == $coded_default_value &&
$info['source_migration'] == $coded_source_migration &&
(!$xml || ($xml && ($info['xpath'] == $coded_xpath))) &&
$dnm_matches) {
continue;
}
}
@@ -1401,17 +1418,17 @@ function migrate_ui_edit_mappings_submit(&$form, &$form_state) {
// losing important bits.
$mapping = NULL;
if (isset($existing_mappings[$destination_field]) &&
$issue_group_values[$destination_field] != 0) {
$issue_group_values[$destination_field] != 0) {
/** @var MigrateFieldMapping $old_mapping */
$old_mapping = $existing_mappings[$destination_field];
if ($source_field == $old_mapping->getSourceField() &&
$default_values[$destination_field] == $old_mapping->getDefaultValue() &&
$source_migrations[$destination_field] == $old_mapping->getSourceMigration() &&
(!$xml || ($xml && ($xpaths[$destination_field] == $old_mapping->getXpath())))) {
$default_values[$destination_field] == $old_mapping->getDefaultValue() &&
$source_migrations[$destination_field] == $old_mapping->getSourceMigration() &&
(!$xml || ($xml && ($xpaths[$destination_field] == $old_mapping->getXpath())))) {
// First, if this mapping matches a previously-stored mapping, we want to
// preserve it as it was originally stored.
if ($old_mapping->getMappingSource() ==
MigrateFieldMapping::MAPPING_SOURCE_DB) {
MigrateFieldMapping::MAPPING_SOURCE_DB) {
$mapping = $old_mapping;
}
// If it matches a coded mapping, then we don't want to save it at all.
@@ -1439,7 +1456,7 @@ function migrate_ui_edit_mappings_submit(&$form, &$form_state) {
}
if ($source_migrations[$destination_field] &&
$source_migrations[$destination_field] != '-1') {
$source_migrations[$destination_field] != '-1') {
$mapping->sourceMigration($source_migrations[$destination_field]);
}
@@ -1452,7 +1469,7 @@ function migrate_ui_edit_mappings_submit(&$form, &$form_state) {
$code_ignored = FALSE;
foreach ($coded_mappings as $destination_field => $mapping) {
if (is_numeric($destination_field) &&
$mapping->getSourceField() == $source_field) {
$mapping->getSourceField() == $source_field) {
$code_ignored = TRUE;
}
}
@@ -1548,8 +1565,13 @@ function theme_migrate_ui_field_mapping_form($variables) {
$form = $variables['field_mappings'];
$elements = element_children($form);
if (!empty($elements)) {
$header = array(t('DNM'), t('Destination field'), t('Source field'),
t('Default value'), t('Source migration'));
$header = array(
t('DNM'),
t('Destination field'),
t('Source field'),
t('Default value'),
t('Source migration'),
);
if (!empty($form['#is_xml_migration'])) {
$header[] = t('Xpath');
}
@@ -1596,7 +1618,11 @@ function theme_migrate_ui_field_mapping_dependencies($variables) {
$row[] = drupal_render($form[$mapping_key]);
$rows[] = $row;
}
$output .= theme('table', array('rows' => $rows, 'header' => $header, 'empty' => t('No other migrations were found.')));
$output .= theme('table', array(
'rows' => $rows,
'header' => $header,
'empty' => t('No other migrations were found.'),
));
$output .= drupal_render_children($form);
return $output;
@@ -1607,7 +1633,7 @@ function theme_migrate_ui_field_mapping_dependencies($variables) {
*/
function migrate_ui_messages($group_name, $migration_name) {
drupal_set_title(t('Import messages for !migration',
array('!migration' => $migration_name)));
array('!migration' => $migration_name)));
$build = $rows = array();
@@ -1624,7 +1650,7 @@ function migrate_ui_messages($group_name, $migration_name) {
// Add a table header for each source key in the migration's map.
foreach ($source_key as $key => $map_info) {
$header[] = array(
'data' => filter_xss_admin($map_info['description']),
'data' => isset($map_info['description']) ? filter_xss_admin($map_info['description']) : t('Source ID'),
'field' => $source_key_map[$key],
'sort' => 'asc',
);
@@ -1635,13 +1661,13 @@ function migrate_ui_messages($group_name, $migration_name) {
// TODO: need a general MigrateMap API
$messages = $migration->getMap()->getConnection()
->select($migration->getMap()->getMessageTable(), 'msg')
->extend('PagerDefault')
->extend('TableSort')
->orderByHeader($header)
->limit(500)
->fields('msg')
->execute();
->select($migration->getMap()->getMessageTable(), 'msg')
->extend('PagerDefault')
->extend('TableSort')
->orderByHeader($header)
->limit(500)
->fields('msg')
->execute();
foreach ($messages as $message) {
$classes[] = $message->level <= MigrationBase::MESSAGE_WARNING ? 'migrate-error' : '';
@@ -1732,17 +1758,17 @@ function migrate_ui_configure_form($form, &$form_state) {
$migrations = array();
$result = db_select('migrate_status', 'ms')
->fields('ms', array('class_name', 'machine_name'))
->execute();
->fields('ms', array('class_name', 'machine_name'))
->execute();
$migration_list = '';
foreach ($result as $row) {
if (!class_exists($row->class_name)) {
$migrations[] = $row->machine_name;
$migration_list .= '<li>' . t('!migration (class !class)',
array(
'!migration' => filter_xss_admin($row->machine_name),
'!class' => filter_xss_admin($row->class_name),
)) . "</li>\n";
array(
'!migration' => filter_xss_admin($row->machine_name),
'!class' => filter_xss_admin($row->class_name),
)) . "</li>\n";
}
}
@@ -1906,18 +1932,18 @@ function migrate_ui_configure_form($form, &$form_state) {
);
$disabled = unserialize(variable_get('migrate_disabled_handlers',
serialize(array())));
serialize(array())));
$class_list = _migrate_class_list('MigrateDestinationHandler');
$rows = array();
$default_values = array();
foreach ($class_list as $class_name => $handler) {
$row = array();
$module = db_select('registry', 'r')
->fields('r', array('module'))
->condition('name', $class_name)
->condition('type', 'class')
->execute()
->fetchField();
->fields('r', array('module'))
->condition('name', $class_name)
->condition('type', 'class')
->execute()
->fetchField();
$row['module'] = check_plain($module);
$row['class'] = check_plain($class_name);
$row['types'] = filter_xss_admin(implode(', ', $handler->getTypesHandled()));
@@ -1950,11 +1976,11 @@ function migrate_ui_configure_form($form, &$form_state) {
foreach ($class_list as $class_name => $handler) {
$row = array();
$module = db_select('registry', 'r')
->fields('r', array('module'))
->condition('name', $class_name)
->condition('type', 'class')
->execute()
->fetchField();
->fields('r', array('module'))
->condition('name', $class_name)
->condition('type', 'class')
->execute()
->fetchField();
$row['module'] = check_plain($module);
$row['class'] = check_plain($class_name);
$row['types'] = filter_xss_admin(implode(', ', $handler->getTypesHandled()));
@@ -1992,8 +2018,8 @@ function migrate_ui_configure_register_submit($form, &$form_state) {
*/
function migrate_ui_configure_deregister_submit($form, &$form_state) {
$result = db_select('migrate_status', 'ms')
->fields('ms', array('class_name', 'machine_name'))
->execute();
->fields('ms', array('class_name', 'machine_name'))
->execute();
foreach ($result as $row) {
if (!class_exists($row->class_name)) {
migrate_ui_deregister_migration($row->machine_name);
@@ -2007,7 +2033,7 @@ function migrate_ui_configure_deregister_submit($form, &$form_state) {
*/
function migrate_ui_configure_settings_submit($form, &$form_state) {
variable_set('migrate_deprecation_warnings',
$form_state['values']['deprecation_warnings']);
$form_state['values']['deprecation_warnings']);
drupal_set_message(t('Migration settings saved.'));
}

View File

@@ -93,7 +93,8 @@ function migrate_ui_wizard_next_submit($form, &$form_state) {
}
/**
* Submit handler for the Save settings button. Register the migrations that were
* Submit handler for the Save settings button. Register the migrations that
* were
* (implicitly) defined along the way and redirect to the Migrate dashboard.
*/
function migrate_ui_wizard_submit($form, &$form_state) {
@@ -101,7 +102,7 @@ function migrate_ui_wizard_submit($form, &$form_state) {
$wizard = $form_state['wizard'];
$wizard->formSaveSettings();
$form_state['redirect'] = 'admin/content/migrate/groups/' .
$wizard->getGroupName();
$wizard->getGroupName();
}
/**
@@ -115,7 +116,7 @@ function migrate_ui_wizard_migrate_submit($form, &$form_state) {
$wizard->formSaveSettings();
$wizard->formPerformImport();
$form_state['redirect'] = 'admin/content/migrate/groups/' .
$wizard->getGroupName();
$wizard->getGroupName();
}
/**
@@ -124,6 +125,7 @@ function migrate_ui_wizard_migrate_submit($form, &$form_state) {
* WordPress, etc.).
*/
abstract class MigrateUIWizard {
/**
* We maintain a doubly-linked list of wizard steps, both to support
* previous/next, and to easily insert steps dynamically.
@@ -185,6 +187,7 @@ abstract class MigrateUIWizard {
* @var string
*/
protected $groupName = 'default';
public function getGroupName() {
return $this->groupName;
}
@@ -217,6 +220,7 @@ abstract class MigrateUIWizard {
* @var array
*/
protected $extenders = array();
public function getExtender($extender_class) {
if (isset($this->extenders[$extender_class])) {
return $this->extenders[$extender_class];
@@ -234,7 +238,8 @@ abstract class MigrateUIWizard {
*/
abstract public function getSourceName();
public function __construct() {}
public function __construct() {
}
/**
* Add a wizard extender.
@@ -373,13 +378,14 @@ abstract class MigrateUIWizard {
$form['title'] = array(
'#prefix' => '<h2>',
'#markup' => t('Step @step: @step_name',
array(
'@step' => $this->stepNumber,
'@step_name' => $this->currentStep->getName())),
array(
'@step' => $this->stepNumber,
'@step_name' => $this->currentStep->getName(),
)),
'#suffix' => '</h2>',
);
$form += call_user_func($form_method, $form_state);
$form += call_user_func_array($form_method, array(&$form_state));
$form['actions'] = array('#type' => 'actions');
@@ -441,7 +447,7 @@ abstract class MigrateUIWizard {
}
if (is_callable($validate_method)) {
call_user_func($validate_method, $form_state);
call_user_func_array($validate_method, array(&$form_state));
}
}
@@ -459,11 +465,11 @@ abstract class MigrateUIWizard {
// called.
if (is_subclass_of($info['class_name'], 'Migration')) {
Migration::registerMigration($info['class_name'], $machine_name,
$info['arguments']);
$info['arguments']);
}
else {
MigrationBase::registerMigration($info['class_name'], $machine_name,
$info['arguments']);
$info['arguments']);
}
};
menu_rebuild();
@@ -479,7 +485,10 @@ abstract class MigrateUIWizard {
foreach ($migrations as $migration) {
$group_name = $migration->getGroup()->getName();
if ($group_name == $this->groupName) {
$operations[] = array('migrate_ui_batch', array('import', $migration->getMachineName(), NULL, 0));
$operations[] = array(
'migrate_ui_batch',
array('import', $migration->getMachineName(), NULL, 0),
);
}
}
@@ -544,6 +553,7 @@ abstract class MigrateUIWizard {
* Class representing one step of a wizard.
*/
class MigrateUIStep {
/**
* A translatable string briefly describing this step, to be used in the page
* title for the step form.
@@ -551,6 +561,7 @@ class MigrateUIStep {
* @var string
*/
protected $name;
public function getName() {
return $this->name;
}
@@ -561,6 +572,7 @@ class MigrateUIStep {
* @var string
*/
protected $formMethod;
public function getFormMethod() {
return $this->formMethod;
}
@@ -572,9 +584,11 @@ class MigrateUIStep {
* @var array
*/
protected $formValues;
public function getFormValues() {
return $this->formValues;
}
public function setFormValues($form_values) {
$this->formValues = $form_values;
}
@@ -587,6 +601,7 @@ class MigrateUIStep {
* @var mixed
*/
protected $context;
public function getContext() {
return $this->context;
}
@@ -627,6 +642,7 @@ class MigrateUIStep {
*
*/
abstract class MigrateUIWizardExtender {
/**
* Reference to the wizard object that this extender applies to.
*/

View File

@@ -9,6 +9,7 @@
* Destination class implementing migration into {block_custom}.
*/
class MigrateDestinationCustomBlock extends MigrateDestination {
static public function getKeySchema() {
return array(
'bid' => array(
@@ -19,6 +20,7 @@ class MigrateDestinationCustomBlock extends MigrateDestination {
),
);
}
public function __construct() {
parent::__construct();
}
@@ -33,6 +35,7 @@ class MigrateDestinationCustomBlock extends MigrateDestination {
*
* @param Migration $migration
* Optionally, the migration containing this destination.
*
* @return array
* Keys: machine names of the fields (to be passed to addFieldMapping)
* Values: Human-friendly descriptions of the fields.
@@ -51,9 +54,11 @@ class MigrateDestinationCustomBlock extends MigrateDestination {
* Import a single row.
*
* @param $block
* Custom block object to build. Prefilled with any fields mapped in the Migration.
* Custom block object to build. Prefilled with any fields mapped in the
* Migration.
* @param $row
* Raw source data object - passed through to prepare/complete handlers.
*
* @return array
* Array of key fields of the object that was saved if
* successful. FALSE on failure.
@@ -75,8 +80,8 @@ class MigrateDestinationCustomBlock extends MigrateDestination {
}
$block_to_update = (object) $old_block;
foreach ($old_block as $key => $value) {
if (!isset($block->$key)) {
$block->$key = $old_block[$key];
if (!isset($block->{$key})) {
$block->{$key} = $old_block[$key];
}
}
}
@@ -230,8 +235,17 @@ class MigrateDestinationCustomBlock extends MigrateDestination {
public function deleteMultipleCustomBlocks(array $bids) {
db_delete('block_custom')->condition('bid', $bids, 'IN')->execute();
db_delete('block')->condition('module', 'block')->condition('delta', $bids, 'IN')->execute();
db_delete('block_role')->condition('module', 'block')->condition('delta', $bids, 'IN')->execute();
db_delete('block_node_type')->condition('module', 'block')->condition('delta', $bids, 'IN')->execute();
db_delete('block')
->condition('module', 'block')
->condition('delta', $bids, 'IN')
->execute();
db_delete('block_role')
->condition('module', 'block')
->condition('delta', $bids, 'IN')
->execute();
db_delete('block_node_type')
->condition('module', 'block')
->condition('delta', $bids, 'IN')
->execute();
}
}

View File

@@ -12,6 +12,7 @@
* Destination class implementing migration into comments.
*/
class MigrateDestinationComment extends MigrateDestinationEntity {
static public function getKeySchema() {
return array(
'cid' => array(
@@ -24,6 +25,7 @@ class MigrateDestinationComment extends MigrateDestinationEntity {
/**
* Save the original setting of comment_maintain_node_statistics
*
* @var boolean
*/
protected $maintainNodeStatistics;
@@ -58,6 +60,7 @@ class MigrateDestinationComment extends MigrateDestinationEntity {
*
* @param Migration $migration
* Optionally, the migration containing this destination.
*
* @return array
* Keys: machine names of the fields (to be passed to addFieldMapping)
* Values: Human-friendly descriptions of the fields.
@@ -66,33 +69,33 @@ class MigrateDestinationComment extends MigrateDestinationEntity {
$fields = array();
// First the core (comment table) properties
$fields['cid'] = t('<a href="@doc">Existing comment ID</a>',
array('@doc' => 'http://drupal.org/node/1349714#cid'));
array('@doc' => 'http://drupal.org/node/1349714#cid'));
$fields['nid'] = t('<a href="@doc">Node (by Drupal ID)</a>',
array('@doc' => 'http://drupal.org/node/1349714#nid'));
array('@doc' => 'http://drupal.org/node/1349714#nid'));
$fields['uid'] = t('<a href="@doc">User (by Drupal ID)</a>',
array('@doc' => 'http://drupal.org/node/1349714#uid'));
array('@doc' => 'http://drupal.org/node/1349714#uid'));
$fields['pid'] = t('<a href="@doc">Parent (by Drupal ID)</a>',
array('@doc' => 'http://drupal.org/node/1349714#pid'));
array('@doc' => 'http://drupal.org/node/1349714#pid'));
$fields['subject'] = t('<a href="@doc">Subject</a>',
array('@doc' => 'http://drupal.org/node/1349714#subject'));
array('@doc' => 'http://drupal.org/node/1349714#subject'));
$fields['created'] = t('<a href="@doc">Created timestamp</a>',
array('@doc' => 'http://drupal.org/node/1349714#created'));
array('@doc' => 'http://drupal.org/node/1349714#created'));
$fields['changed'] = t('<a href="@doc">Modified timestamp</a>',
array('@doc' => 'http://drupal.org/node/1349714#changed'));
array('@doc' => 'http://drupal.org/node/1349714#changed'));
$fields['status'] = t('<a href="@doc">Status</a>',
array('@doc' => 'http://drupal.org/node/1349714#status'));
array('@doc' => 'http://drupal.org/node/1349714#status'));
$fields['hostname'] = t('<a href="@doc">Hostname/IP address</a>',
array('@doc' => 'http://drupal.org/node/1349714#hostname'));
array('@doc' => 'http://drupal.org/node/1349714#hostname'));
$fields['name'] = t('<a href="@doc">User name (not username)</a>',
array('@doc' => 'http://drupal.org/node/1349714#name'));
array('@doc' => 'http://drupal.org/node/1349714#name'));
$fields['mail'] = t('<a href="@doc">Email address</a>',
array('@doc' => 'http://drupal.org/node/1349714#mail'));
array('@doc' => 'http://drupal.org/node/1349714#mail'));
$fields['homepage'] = t('<a href="@doc">Homepage</a>',
array('@doc' => 'http://drupal.org/node/1349714#homepage'));
array('@doc' => 'http://drupal.org/node/1349714#homepage'));
$fields['language'] = t('<a href="@doc">Language</a>',
array('@doc' => 'http://drupal.org/node/1349714#language'));
array('@doc' => 'http://drupal.org/node/1349714#language'));
$fields['thread'] = t('<a href="@doc">Thread</a>',
array('@doc' => 'http://drupal.org/node/1349714#thread'));
array('@doc' => 'http://drupal.org/node/1349714#thread'));
// Then add in anything provided by handlers
$fields += migrate_handler_invoke_all('Entity', 'fields', $this->entityType, $this->bundle, $migration);
@@ -120,12 +123,14 @@ class MigrateDestinationComment extends MigrateDestinationEntity {
* Import a single comment.
*
* @param $comment
* Comment object to build. Prefilled with any fields mapped in the Migration.
* Comment object to build. Prefilled with any fields mapped in the
* Migration.
* @param $row
* Raw source data object - passed through to prepare/complete handlers.
*
* @return array
* Array of key fields (cid only in this case) of the comment that was saved if
* successful. FALSE on failure.
* Array of key fields (cid only in this case) of the comment that was saved
* if successful. FALSE on failure.
*/
public function import(stdClass $comment, stdClass $row) {
$migration = Migration::currentMigration();
@@ -134,7 +139,10 @@ class MigrateDestinationComment extends MigrateDestinationEntity {
if (isset($comment->cid)) {
if ($comment->cid != $row->migrate_map_destid1) {
throw new MigrateException(t("Incoming cid !cid and map destination nid !destid1 don't match",
array('!cid' => $comment->cid, '!destid1' => $row->migrate_map_destid1)));
array(
'!cid' => $comment->cid,
'!destid1' => $row->migrate_map_destid1,
)));
}
}
else {
@@ -174,7 +182,7 @@ class MigrateDestinationComment extends MigrateDestinationEntity {
}
$this->prepare($comment, $row);
foreach ($rawcomment as $field => $value) {
$old_comment->$field = $comment->$field;
$old_comment->{$field} = $comment->{$field};
}
$comment = $old_comment;
}
@@ -190,8 +198,8 @@ class MigrateDestinationComment extends MigrateDestinationEntity {
'pid' => 0,
);
foreach ($defaults as $field => $value) {
if (!isset($comment->$field)) {
$comment->$field = $value;
if (!isset($comment->{$field})) {
$comment->{$field} = $value;
}
}
@@ -273,8 +281,8 @@ class MigrateDestinationComment extends MigrateDestinationEntity {
/**
* Updating node statistics on every comment imported or rolled back is
* expensive. We disable node statistics while performing imports and rollbacks,
* then re-enable and compute them in bulk when done.
* expensive. We disable node statistics while performing imports and
* rollbacks, then re-enable and compute them in bulk when done.
*/
protected function disableStatistics() {
// If maintaining node statistics is enabled, temporarily disable it
@@ -316,7 +324,7 @@ class MigrateDestinationComment extends MigrateDestinationEntity {
GROUP BY c.nid
) AS c2 ON c.nid = c2.nid AND c.created=c2.created
)";
break;
break;
default:
$sql = "
@@ -333,8 +341,7 @@ class MigrateDestinationComment extends MigrateDestinationEntity {
}
try {
db_query($sql, array(':published' => COMMENT_PUBLISHED));
}
catch (Exception $e) {
} catch (Exception $e) {
// Our edge case has been hit. A Postgres migration has likely just
// lost data. Let the user know.
Migration::displayMessage(t('Failed to update node comment statistics: !message',
@@ -360,6 +367,7 @@ class MigrateDestinationComment extends MigrateDestinationEntity {
}
class MigrateCommentNodeHandler extends MigrateDestinationHandler {
public function __construct() {
$this->registerTypes(array('node'));
}

View File

@@ -10,12 +10,14 @@
* Field API-related functions.
*/
abstract class MigrateDestinationEntity extends MigrateDestination {
/**
* The entity type (node, user, taxonomy_term, etc.) of the destination.
*
* @var string
*/
protected $entityType;
public function getEntityType() {
return $this->entityType;
}
@@ -26,6 +28,7 @@ abstract class MigrateDestinationEntity extends MigrateDestination {
* @var string
*/
protected $bundle;
public function getBundle() {
return $this->bundle;
}
@@ -36,6 +39,7 @@ abstract class MigrateDestinationEntity extends MigrateDestination {
* @var string
*/
protected $language;
public function getLanguage() {
return $this->language;
}
@@ -46,6 +50,7 @@ abstract class MigrateDestinationEntity extends MigrateDestination {
* @var int
*/
protected $textFormat;
public function getTextFormat() {
return $this->textFormat;
}
@@ -125,12 +130,12 @@ abstract class MigrateDestinationEntity extends MigrateDestination {
// Add source keys for debugging and identification of migrated data by hooks.
/* TODO: Restore
foreach ($migration->sourceKeyMap() as $field_name => $key_name) {
$keys[$key_name] = $source_row->$field_name;
$keys[$key_name] = $source_row->{$field_name};
}
*/
$migration = Migration::currentMigration();
$entity->migrate = array(
// 'source_keys' => $keys,
// 'source_keys' => $keys,
'machineName' => $migration->getMachineName(),
);
@@ -168,8 +173,7 @@ abstract class MigrateDestinationEntity extends MigrateDestination {
if (method_exists($migration, 'complete')) {
try {
$migration->complete($entity, $source_row);
}
catch (Exception $e) {
} catch (Exception $e) {
// If we catch any errors here, save the messages without letting
// the exception prevent the saving of the entity being recorded.
$migration->saveMessage($e->getMessage());
@@ -190,17 +194,14 @@ abstract class MigrateDestinationEntity extends MigrateDestination {
static public function fieldAttachValidate($entity_type, $entity) {
try {
field_attach_validate($entity_type, $entity);
}
catch (FieldValidationException $e) {
} catch (FieldValidationException $e) {
$migration = Migration::currentMigration();
foreach ($e->errors as $field_name => $field_errors) {
foreach ($field_errors as $langcode => $errors) {
foreach ($errors as $delta => $error_list) {
foreach ($error_list as $index => $error) {
$message = $error['message'];
$migration->saveMessage(t('Field validation error for !field_name: !message',
array('!field_name' => $field_name, '!message' => $message)));
}
foreach ($e->errors as $field_name => $error_list) {
if (is_array($error_list)) {
foreach ($error_list as $index => $error) {
$message = $error['message'];
$migration->saveMessage(t('Field validation error for !field_name: !message',
array('!field_name' => $field_name, '!message' => $message)));
}
}
}

View File

@@ -6,6 +6,7 @@
*/
class MigrateFieldsEntityHandler extends MigrateDestinationHandler {
public function __construct() {
$this->registerTypes(array('entity'));
}
@@ -33,10 +34,10 @@ class MigrateFieldsEntityHandler extends MigrateDestinationHandler {
$fields_found = FALSE;
foreach ($class_list as $class_name => $handler) {
if (!in_array($class_name, $disabled) && $handler->handlesType($type)
&& method_exists($handler, 'fields')) {
&& method_exists($handler, 'fields')) {
migrate_instrument_start($class_name . '->fields');
$subfields = call_user_func(array($handler, 'fields'), $type,
$instance, $migration);
$instance, $migration);
migrate_instrument_stop($class_name . '->fields');
foreach ($subfields as $subfield_name => $subfield_label) {
$fields[$machine_name . ':' . $subfield_name] = $subfield_label;
@@ -49,7 +50,7 @@ class MigrateFieldsEntityHandler extends MigrateDestinationHandler {
migrate_instrument_start('MigrateDefaultFieldHandler->fields');
$subfields = call_user_func(
array(new MigrateDefaultFieldHandler, 'fields'), $type, $instance,
$migration);
$migration);
migrate_instrument_stop('MigrateDefaultFieldHandler->fields');
foreach ($subfields as $subfield_name => $subfield_label) {
$fields[$machine_name . ':' . $subfield_name] = $subfield_label;
@@ -71,12 +72,12 @@ class MigrateFieldsEntityHandler extends MigrateDestinationHandler {
foreach ($instances as $machine_name => $instance) {
if (property_exists($entity, $machine_name)) {
// Normalize to an array
if (!is_array($entity->$machine_name)) {
$entity->$machine_name = array($entity->$machine_name);
if (!is_array($entity->{$machine_name})) {
$entity->{$machine_name} = array($entity->{$machine_name});
}
$field_info = field_info_field($machine_name);
$entity->$machine_name = migrate_field_handler_invoke_all($entity, $field_info,
$instance, $entity->$machine_name);
$entity->{$machine_name} = migrate_field_handler_invoke_all($entity, $field_info,
$instance, $entity->{$machine_name});
}
}
migrate_instrument_stop('MigrateDestinationEntity->prepareFields');
@@ -93,12 +94,12 @@ class MigrateFieldsEntityHandler extends MigrateDestinationHandler {
foreach ($instances as $machine_name => $instance) {
if (property_exists($entity, $machine_name)) {
// Normalize to an array
if (!is_array($entity->$machine_name)) {
$entity->$machine_name = array($entity->$machine_name);
if (!is_array($entity->{$machine_name})) {
$entity->{$machine_name} = array($entity->{$machine_name});
}
$field_info = field_info_field($machine_name);
migrate_field_handler_invoke_all($entity, $field_info,
$instance, $entity->$machine_name, 'complete');
$instance, $entity->{$machine_name}, 'complete');
}
}
migrate_instrument_stop('MigrateDestinationEntity->completeFields');
@@ -106,6 +107,7 @@ class MigrateFieldsEntityHandler extends MigrateDestinationHandler {
}
abstract class MigrateFieldHandler extends MigrateHandler {
// Derived classes are expected to implement one or both of the prepare/complete
// handlers.
@@ -118,12 +120,14 @@ abstract class MigrateFieldHandler extends MigrateHandler {
* @param $entity
* @param $field_info
* @param $arguments
*
* @return string language code
*/
function getFieldLanguage($entity, $field_info, array $arguments) {
$migration = Migration::currentMigration();
switch (TRUE) {
case !field_is_translatable($migration->getDestination()->getEntityType(), $field_info):
case !field_is_translatable($migration->getDestination()
->getEntityType(), $field_info):
return LANGUAGE_NONE;
case isset($arguments['language']):
return $arguments['language'];
@@ -140,7 +144,9 @@ abstract class MigrateFieldHandler extends MigrateHandler {
* A fallback field handler to do basic copying of field data.
*/
class MigrateDefaultFieldHandler extends MigrateFieldHandler {
public function __construct() {}
public function __construct() {
}
/**
* Implements MigrateFieldHandler::fields().
@@ -230,6 +236,7 @@ class MigrateDefaultFieldHandler extends MigrateFieldHandler {
*
* To use this class just extend it and pass key where the field's value should
* be stored to the constructor, then register the type(s):
*
* @code
* class MigrateLinkFieldHandler extends MigrateSimpleFieldHandler {
* public function __construct() {
@@ -240,6 +247,7 @@ class MigrateDefaultFieldHandler extends MigrateFieldHandler {
* @endcode
*/
abstract class MigrateSimpleFieldHandler extends MigrateFieldHandler {
protected $fieldValueKey = 'value';
protected $skipEmpty = FALSE;
@@ -294,6 +302,7 @@ abstract class MigrateSimpleFieldHandler extends MigrateFieldHandler {
* Returns TRUE only for values which are not NULL.
*
* @param $value
*
* @return bool
*/
protected function notNull($value) {
@@ -302,6 +311,7 @@ abstract class MigrateSimpleFieldHandler extends MigrateFieldHandler {
}
class MigrateTextFieldHandler extends MigrateFieldHandler {
public function __construct() {
$this->registerTypes(array('text', 'text_long', 'text_with_summary'));
}
@@ -330,6 +340,7 @@ class MigrateTextFieldHandler extends MigrateFieldHandler {
* @param Migration $migration
* The migration context for the parent field. We can look at the mappings
* and determine which subfields are relevant.
*
* @return array
*/
public function fields($type, $instance, $migration = NULL) {
@@ -345,7 +356,7 @@ class MigrateTextFieldHandler extends MigrateFieldHandler {
$field = field_info_field($instance['field_name']);
if (field_is_translatable($instance['entity_type'], $field)) {
$fields['language'] = t('Subfield: <a href="@doc">Language for the field</a>',
array('@doc' => 'http://drupal.org/node/1224042#language'));
array('@doc' => 'http://drupal.org/node/1224042#language'));
}
return $fields;
}
@@ -382,7 +393,7 @@ class MigrateTextFieldHandler extends MigrateFieldHandler {
if (is_array($arguments['format'])) {
$format = $arguments['format'][$delta];
}
else{
else {
$format = $arguments['format'];
}
}
@@ -393,6 +404,11 @@ class MigrateTextFieldHandler extends MigrateFieldHandler {
$format = NULL;
}
$item['format'] = $item['value_format'] = $format;
// If the value is an array, which it might be if the destination entity
// was loaded via entity_load(), ensure we're handling a string.
if (is_array($value) && !empty($value[0]) && array_key_exists('value', $value[0])) {
$value = $value[0]['value'];
}
// Make sure the value will fit
if ($max_length) {
$item['value'] = drupal_substr($value, 0, $max_length);
@@ -401,8 +417,11 @@ class MigrateTextFieldHandler extends MigrateFieldHandler {
if ($value_length > $max_length) {
$migration->saveMessage(
t('Value for field !field exceeds max length of !max_length, actual length is !length',
array('!field' => $instance['field_name'], '!max_length' => $max_length,
'!length' => $value_length)),
array(
'!field' => $instance['field_name'],
'!max_length' => $max_length,
'!length' => $value_length,
)),
Migration::MESSAGE_INFORMATIONAL);
}
}
@@ -426,17 +445,28 @@ class MigrateTextFieldHandler extends MigrateFieldHandler {
}
class MigrateValueFieldHandler extends MigrateSimpleFieldHandler {
public function __construct() {
parent::__construct(array(
'value_key' => 'value',
'skip_empty' => FALSE,
));
$this->registerTypes(array('value', 'list', 'list_boolean', 'list_integer',
'list_float', 'list_text', 'number_integer', 'number_decimal', 'number_float'));
$this->registerTypes(array(
'value',
'list',
'list_boolean',
'list_integer',
'list_float',
'list_text',
'number_integer',
'number_decimal',
'number_float',
));
}
}
class MigrateTaxonomyTermReferenceFieldHandler extends MigrateFieldHandler {
public function __construct() {
$this->registerTypes(array('taxonomy_term_reference'));
}
@@ -451,6 +481,7 @@ class MigrateTaxonomyTermReferenceFieldHandler extends MigrateFieldHandler {
* @param Migration $migration
* The migration context for the parent field. We can look at the mappings
* and determine which subfields are relevant.
*
* @return array
*/
public function fields($type, $instance, $migration = NULL) {
@@ -575,6 +606,7 @@ class MigrateTaxonomyTermReferenceFieldHandler extends MigrateFieldHandler {
* dealing with the file entity to an embedded MigrateFileInterface instance.
*/
abstract class MigrateFileFieldBaseHandler extends MigrateFieldHandler {
/**
* Implementation of MigrateFieldHandler::fields().
*
@@ -585,6 +617,7 @@ abstract class MigrateFileFieldBaseHandler extends MigrateFieldHandler {
* @param Migration $migration
* The migration context for the parent field. We can look at the mappings
* and determine which subfields are relevant.
*
* @return array
*/
public function fields($type, $instance, $migration = NULL) {
@@ -673,8 +706,12 @@ abstract class MigrateFileFieldBaseHandler extends MigrateFieldHandler {
}
else {
$migration->saveMessage(
t('No data for subfield %key at row %delta for field %field',
array('%key' => $key, '%delta' => $delta, '%field' => $field_info['field_name'])),
t('No data for subfield %key at row %delta for field %field',
array(
'%key' => $key,
'%delta' => $delta,
'%field' => $field_info['field_name'],
)),
Migration::MESSAGE_WARNING);
}
}
@@ -710,6 +747,7 @@ abstract class MigrateFileFieldBaseHandler extends MigrateFieldHandler {
* Field API info on the general field.
* @param $instance
* Field API info on the field instance for this entity type.
*
* @return string
* Directory relative to the Drupal public files directory.
*/
@@ -743,6 +781,7 @@ abstract class MigrateFileFieldBaseHandler extends MigrateFieldHandler {
* Handle for file fields.
*/
class MigrateFileFieldHandler extends MigrateFileFieldBaseHandler {
public function __construct() {
$this->registerTypes(array('file'));
}
@@ -758,6 +797,7 @@ class MigrateFileFieldHandler extends MigrateFileFieldBaseHandler {
* @param Migration $migration
* The migration context for the parent field. We can look at the mappings
* and determine which subfields are relevant.
*
* @return array
*/
public function fields($type, $instance, $migration = NULL) {
@@ -806,6 +846,7 @@ class MigrateFileFieldHandler extends MigrateFileFieldBaseHandler {
* Handle for image fields;
*/
class MigrateImageFieldHandler extends MigrateFileFieldBaseHandler {
public function __construct() {
$this->registerTypes(array('image'));
}
@@ -821,6 +862,7 @@ class MigrateImageFieldHandler extends MigrateFileFieldBaseHandler {
* @param Migration $migration
* The migration context for the parent field. We can look at the mappings
* and determine which subfields are relevant.
*
* @return array
*/
public function fields($type, $instance, $migration = NULL) {
@@ -859,6 +901,7 @@ class MigrateImageFieldHandler extends MigrateFileFieldBaseHandler {
}
class MigrateNodeReferenceFieldHandler extends MigrateSimpleFieldHandler {
public function __construct() {
parent::__construct(array(
'value_key' => 'nid',
@@ -873,6 +916,7 @@ class MigrateNodeReferenceFieldHandler extends MigrateSimpleFieldHandler {
}
class MigrateUserReferenceFieldHandler extends MigrateSimpleFieldHandler {
public function __construct() {
parent::__construct(array(
'value_key' => 'uid',

View File

@@ -12,6 +12,7 @@
* a Drupal file entity (creating the entity if necessary).
*/
interface MigrateFileInterface {
/**
* Return a list of subfields and options specific to this implementation,
* keyed by name.
@@ -35,6 +36,7 @@ interface MigrateFileInterface {
}
abstract class MigrateFileBase implements MigrateFileInterface {
/**
* Extension of the core FILE_EXISTS_* constants, offering an alternative to
* reuse the existing file if present as-is (core only offers the options of
@@ -99,6 +101,7 @@ abstract class MigrateFileBase implements MigrateFileInterface {
* Path to the Drupal copy of the file.
* @param $owner
* Uid of the file owner.
*
* @return stdClass
* A file object ready to be saved.
*/
@@ -130,7 +133,7 @@ abstract class MigrateFileBase implements MigrateFileInterface {
// If we are replacing or reusing an existing filesystem entry,
// also re-use its database record.
if ($this->fileReplace == FILE_EXISTS_REPLACE ||
$this->fileReplace == self::FILE_EXISTS_REUSE) {
$this->fileReplace == self::FILE_EXISTS_REUSE) {
$existing_files = file_load_multiple(array(), array('uri' => $destination));
if (count($existing_files)) {
$existing = reset($existing_files);
@@ -171,6 +174,7 @@ abstract class MigrateFileBase implements MigrateFileInterface {
* to copy or otherwise use it.
*/
class MigrateFileUriAsIs extends MigrateFileBase {
public function processFile($value, $owner) {
$file = file_save($this->createFileEntity($value, $owner));
return $file;
@@ -181,6 +185,7 @@ class MigrateFileUriAsIs extends MigrateFileBase {
* Handle the degenerate case where we already have a file ID.
*/
class MigrateFileFid extends MigrateFileBase {
/**
* Implementation of MigrateFileInterface::processFile().
*
@@ -188,6 +193,7 @@ class MigrateFileFid extends MigrateFileBase {
* An existing file entity ID (fid).
* @param $owner
* User ID (uid) to be the owner of the file. Ignored in this case.
*
* @return int
* The file entity corresponding to the fid that was passed in.
*/
@@ -201,6 +207,7 @@ class MigrateFileFid extends MigrateFileBase {
* Base class for creating core file entities.
*/
abstract class MigrateFile extends MigrateFileBase {
/**
* The destination directory within Drupal.
*
@@ -232,13 +239,13 @@ abstract class MigrateFile extends MigrateFileBase {
*/
static public function fields() {
return parent::fields() + array(
'destination_dir' => t('Subfield: <a href="@doc">Path within Drupal files directory to store file</a>',
array('@doc' => 'http://drupal.org/node/1540106#destination_dir')),
'destination_file' => t('Subfield: <a href="@doc">Path within destination_dir to store the file.</a>',
array('@doc' => 'http://drupal.org/node/1540106#destination_file')),
'file_replace' => t('Option: <a href="@doc">Value of $replace in that file function. Defaults to FILE_EXISTS_RENAME.</a>',
array('@doc' => 'http://drupal.org/node/1540106#file_replace')),
);
'destination_dir' => t('Subfield: <a href="@doc">Path within Drupal files directory to store file</a>',
array('@doc' => 'http://drupal.org/node/1540106#destination_dir')),
'destination_file' => t('Subfield: <a href="@doc">Path within destination_dir to store the file.</a>',
array('@doc' => 'http://drupal.org/node/1540106#destination_file')),
'file_replace' => t('Option: <a href="@doc">Value of $replace in that file function. Defaults to FILE_EXISTS_RENAME.</a>',
array('@doc' => 'http://drupal.org/node/1540106#file_replace')),
);
}
/**
@@ -246,6 +253,7 @@ abstract class MigrateFile extends MigrateFileBase {
*
* @param $destination
* Destination path within Drupal.
*
* @return bool
* TRUE if the file is successfully saved, FALSE otherwise.
*/
@@ -258,6 +266,7 @@ abstract class MigrateFile extends MigrateFileBase {
* The URI or local filespec of a file to be imported.
* @param $owner
* User ID (uid) to be the owner of the file.
*
* @return object
* The file entity being created or referenced.
*/
@@ -286,9 +295,9 @@ abstract class MigrateFile extends MigrateFileBase {
// Prepare the destination directory.
$destdir = drupal_dirname($destination);
if (!file_prepare_directory($destdir,
FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) {
FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) {
$migration->saveMessage(t('Could not create destination directory for !dest',
array('!dest' => $destination)));
array('!dest' => $destination)));
return FALSE;
}
@@ -330,6 +339,7 @@ abstract class MigrateFile extends MigrateFileBase {
* to be imported to Drupal.
*/
class MigrateFileUri extends MigrateFile {
/**
* The source directory for the file, relative to which the value (source
* file) will be taken.
@@ -390,13 +400,21 @@ class MigrateFileUri extends MigrateFile {
$this->sourcePath = self::urlencode($this->sourcePath);
}
try {
copy($this->sourcePath, $destination);
return TRUE;
}
catch (Exception $e) {
$copied = copy($this->sourcePath, $destination);
if ($copied == FALSE) {
$migration = Migration::currentMigration();
$migration->saveMessage(t('The specified file %file could not be copied to %destination',
array('%file' => $this->sourcePath, '%destination' => $destination)));
}
return $copied;
} catch (Exception $e) {
$migration = Migration::currentMigration();
$migration->saveMessage(t('The specified file %file could not be copied to %destination: "%exception_msg"',
array('%file' => $this->sourcePath, '%destination' => $destination, '%exception_msg' => $e->getMessage())));
array(
'%file' => $this->sourcePath,
'%destination' => $destination,
'%exception_msg' => $e->getMessage(),
)));
return FALSE;
}
}
@@ -431,6 +449,7 @@ class MigrateFileUri extends MigrateFile {
* The URI or local filespec of a file to be imported.
* @param $owner
* User ID (uid) to be the owner of the file.
*
* @return object
* The file entity being created or referenced.
*/
@@ -460,6 +479,7 @@ class MigrateFileUri extends MigrateFile {
* such as image data) to be stored as a real file in Drupal.
*/
class MigrateFileBlob extends MigrateFile {
/**
* The file contents we will be writing to a real file.
*
@@ -472,6 +492,7 @@ class MigrateFileBlob extends MigrateFile {
*
* @param $destination
* Drupal destination path.
*
* @return bool
* TRUE if the file contents were successfully written, FALSE otherwise.
*/
@@ -482,7 +503,7 @@ class MigrateFileBlob extends MigrateFile {
else {
$migration = Migration::currentMigration();
$migration->saveMessage(t('Failed to write blob data to %destination',
array('%destination' => $destination)));
array('%destination' => $destination)));
return FALSE;
}
}
@@ -494,6 +515,7 @@ class MigrateFileBlob extends MigrateFile {
* The file contents to be saved as a file.
* @param $owner
* User ID (uid) to be the owner of the file.
*
* @return object
* File entity being created or referenced.
*/
@@ -508,12 +530,14 @@ class MigrateFileBlob extends MigrateFile {
* Destination class implementing migration into the files table.
*/
class MigrateDestinationFile extends MigrateDestinationEntity {
/**
* File class (MigrateFileUri etc.) doing the dirty wrk.
*
* @var string
*/
protected $fileClass;
public function setFileClass($file_class) {
$this->fileClass = $file_class;
}
@@ -554,10 +578,12 @@ class MigrateDestinationFile extends MigrateDestinationEntity {
}
/**
* Returns a list of fields available to be mapped for the entity type (bundle)
* Returns a list of fields available to be mapped for the entity type
* (bundle)
*
* @param Migration $migration
* Optionally, the migration containing this destination.
*
* @return array
* Keys: machine names of the fields (to be passed to addFieldMapping)
* Values: Human-friendly descriptions of the fields.
@@ -635,6 +661,7 @@ class MigrateDestinationFile extends MigrateDestinationEntity {
* File object to build. Prefilled with any fields mapped in the Migration.
* @param $row
* Raw source data object - passed through to prepare/complete handlers.
*
* @return array
* Array of key fields (fid only in this case) of the file that was saved if
* successful. FALSE on failure.
@@ -646,7 +673,10 @@ class MigrateDestinationFile extends MigrateDestinationEntity {
if (isset($file->fid)) {
if ($file->fid != $row->migrate_map_destid1) {
throw new MigrateException(t("Incoming fid !fid and map destination fid !destid1 don't match",
array('!fid' => $file->fid, '!destid1' => $row->migrate_map_destid1)));
array(
'!fid' => $file->fid,
'!destid1' => $row->migrate_map_destid1,
)));
}
}
else {
@@ -700,7 +730,7 @@ class MigrateDestinationFile extends MigrateDestinationEntity {
$file->preserve_files = FALSE;
$file_class = $this->fileClass;
$source = new $file_class((array)$file, $file);
$source = new $file_class((array) $file, $file);
$file = $source->processFile($file->value, $file->uid);
if (is_object($file) && isset($file->fid)) {

View File

@@ -9,6 +9,7 @@
* Destination class implementing migration into {menu_custom}.
*/
class MigrateDestinationMenu extends MigrateDestination {
static public function getKeySchema() {
return array(
'menu_name' => array(
@@ -35,6 +36,7 @@ class MigrateDestinationMenu extends MigrateDestination {
*
* @param Migration $migration
* Optionally, the migration containing this destination.
*
* @return array
* Keys: machine names of the fields (to be passed to addFieldMapping)
* Values: Human-friendly descriptions of the fields.
@@ -55,6 +57,7 @@ class MigrateDestinationMenu extends MigrateDestination {
* Menu object to build. Prefilled with any fields mapped in the Migration.
* @param $row
* Raw source data object - passed through to prepare/complete handlers.
*
* @return array
* Array of key fields of the object that was saved if
* successful. FALSE on failure.

View File

@@ -9,6 +9,7 @@
* Destination class implementing migration into {menu_links}.
*/
class MigrateDestinationMenuLinks extends MigrateDestination {
static public function getKeySchema() {
return array(
'mlid' => array(
@@ -19,6 +20,7 @@ class MigrateDestinationMenuLinks extends MigrateDestination {
),
);
}
public function __construct() {
parent::__construct();
}
@@ -33,6 +35,7 @@ class MigrateDestinationMenuLinks extends MigrateDestination {
*
* @param Migration $migration
* Optionally, the migration containing this destination.
*
* @return array
* Keys: machine names of the fields (to be passed to addFieldMapping)
* Values: Human-friendly descriptions of the fields.
@@ -72,9 +75,11 @@ class MigrateDestinationMenuLinks extends MigrateDestination {
* Import a single row.
*
* @param $menu_link
* Menu link object to build. Prefilled with any fields mapped in the Migration.
* Menu link object to build. Prefilled with any fields mapped in the
* Migration.
* @param $row
* Raw source data object - passed through to prepare/complete handlers.
*
* @return array
* Array of key fields of the object that was saved if
* successful. FALSE on failure.
@@ -95,9 +100,9 @@ class MigrateDestinationMenuLinks extends MigrateDestination {
throw new MigrateException(t('System-of-record is DESTINATION, and the provided mlid could not be found'));
}
$menu_link_to_update = (object) $old_menu_link;
foreach($old_menu_link as $key => $value) {
if (!isset($menu_link->$key)) {
$menu_link->$key = $old_menu_link[$key];
foreach ($old_menu_link as $key => $value) {
if (!isset($menu_link->{$key})) {
$menu_link->{$key} = $old_menu_link[$key];
}
}
}

View File

@@ -12,6 +12,7 @@
* Destination class implementing migration into nodes.
*/
class MigrateDestinationNode extends MigrateDestinationEntity {
protected $bypassDestIdCheck = FALSE;
static public function getKeySchema() {
@@ -53,6 +54,7 @@ class MigrateDestinationNode extends MigrateDestinationEntity {
*
* @param Migration $migration
* Optionally, the migration containing this destination.
*
* @return array
* Keys: machine names of the fields (to be passed to addFieldMapping)
* Values: Human-friendly descriptions of the fields.
@@ -61,39 +63,39 @@ class MigrateDestinationNode extends MigrateDestinationEntity {
$fields = array();
// First the core (node table) properties
$fields['nid'] = t('Node: <a href="@doc">Existing node ID</a>',
array('@doc' => 'http://drupal.org/node/1349696#nid'));
array('@doc' => 'http://drupal.org/node/1349696#nid'));
$node_type = node_type_load($this->bundle);
if ($node_type->has_title) {
$fields['title'] = t('Node: <a href="@doc">',
array('@doc' => 'http://drupal.org/node/1349696#title'))
. $node_type->title_label . '</a>';
array('@doc' => 'http://drupal.org/node/1349696#title'))
. $node_type->title_label . '</a>';
}
$fields['uid'] = t('<a href="@doc">Authored by (uid)</a>',
array('@doc' => 'http://drupal.org/node/1349696#uid'));
array('@doc' => 'http://drupal.org/node/1349696#uid'));
$fields['created'] = t('<a href="@doc">Created timestamp</a>',
array('@doc' => 'http://drupal.org/node/1349696#created'));
array('@doc' => 'http://drupal.org/node/1349696#created'));
$fields['changed'] = t('<a href="@doc">Modified timestamp</a>',
array('@doc' => 'http://drupal.org/node/1349696#changed'));
array('@doc' => 'http://drupal.org/node/1349696#changed'));
$fields['status'] = t('<a href="@doc">Published</a>',
array('@doc' => 'http://drupal.org/node/1349696#status'));
array('@doc' => 'http://drupal.org/node/1349696#status'));
$fields['promote'] = t('<a href="@doc">Promoted to front page</a>',
array('@doc' => 'http://drupal.org/node/1349696#promote'));
array('@doc' => 'http://drupal.org/node/1349696#promote'));
$fields['sticky'] = t('<a href="@doc">Sticky at top of lists</a>',
array('@doc' => 'http://drupal.org/node/1349696#sticky'));
array('@doc' => 'http://drupal.org/node/1349696#sticky'));
$fields['revision'] = t('<a href="@doc">Create new revision</a>',
array('@doc' => 'http://drupal.org/node/1349696#revision'));
array('@doc' => 'http://drupal.org/node/1349696#revision'));
$fields['log'] = t('<a href="@doc">Revision Log message</a>',
array('@doc' => 'http://drupal.org/node/1349696#log'));
array('@doc' => 'http://drupal.org/node/1349696#log'));
$fields['language'] = t('<a href="@doc">Language (fr, en, ...)</a>',
array('@doc' => 'http://drupal.org/node/1349696#language'));
array('@doc' => 'http://drupal.org/node/1349696#language'));
$fields['tnid'] = t('<a href="@doc">The translation set id for this node</a>',
array('@doc' => 'http://drupal.org/node/1349696#tnid'));
array('@doc' => 'http://drupal.org/node/1349696#tnid'));
$fields['translate'] = t('<a href="@doc">A boolean indicating whether this translation page needs to be updated</a>',
array('@doc' => 'http://drupal.org/node/1349696#translate'));
array('@doc' => 'http://drupal.org/node/1349696#translate'));
$fields['revision_uid'] = t('<a href="@doc">Modified (uid)</a>',
array('@doc' => 'http://drupal.org/node/1349696#revision_uid'));
array('@doc' => 'http://drupal.org/node/1349696#revision_uid'));
$fields['is_new'] = t('Option: <a href="@doc">Indicates a new node with the specified nid should be created</a>',
array('@doc' => 'http://drupal.org/node/1349696#is_new'));
array('@doc' => 'http://drupal.org/node/1349696#is_new'));
// Then add in anything provided by handlers
$fields += migrate_handler_invoke_all('Entity', 'fields', $this->entityType, $this->bundle, $migration);
@@ -123,6 +125,7 @@ class MigrateDestinationNode extends MigrateDestinationEntity {
* Node object to build. Prefilled with any fields mapped in the Migration.
* @param $row
* Raw source data object - passed through to prepare/complete handlers.
*
* @return array
* Array of key fields (nid only in this case) of the node that was saved if
* successful. FALSE on failure.
@@ -136,7 +139,10 @@ class MigrateDestinationNode extends MigrateDestinationEntity {
if (isset($node->nid)) {
if ($node->nid != $row->migrate_map_destid1) {
throw new MigrateException(t("Incoming nid !nid and map destination nid !destid1 don't match",
array('!nid' => $node->nid, '!destid1' => $row->migrate_map_destid1)));
array(
'!nid' => $node->nid,
'!destid1' => $row->migrate_map_destid1,
)));
}
}
else {
@@ -144,13 +150,13 @@ class MigrateDestinationNode extends MigrateDestinationEntity {
}
// Get the existing vid, tnid so updates don't generate notices
$values = db_select('node', 'n')
->fields('n', array('vid', 'tnid'))
->condition('nid', $node->nid)
->execute()
->fetchAssoc();
->fields('n', array('vid', 'tnid'))
->condition('nid', $node->nid)
->execute()
->fetchAssoc();
if (empty($values)) {
throw new MigrateException(t("Incoming node ID !nid no longer exists",
array('!nid' => $node->nid)));
array('!nid' => $node->nid)));
}
$node->vid = $values['vid'];
if (empty($node->tnid)) {
@@ -164,7 +170,7 @@ class MigrateDestinationNode extends MigrateDestinationEntity {
$old_node = node_load($node->nid);
if (empty($old_node)) {
throw new MigrateException(t('System-of-record is DESTINATION, but node !nid does not exist',
array('!nid' => $node->nid)));
array('!nid' => $node->nid)));
}
if (!isset($node->created)) {
$node->created = $old_node->created;
@@ -241,11 +247,11 @@ class MigrateDestinationNode extends MigrateDestinationEntity {
foreach ($old_node as $field => $value) {
// An explicit NULL in the source data means to wipe to old value (i.e.,
// don't copy it over from $old_node)
if (property_exists($node, $field) && $node->$field === NULL) {
if (property_exists($node, $field) && $node->{$field} === NULL) {
// Ignore this field
}
elseif (!isset($node->$field)) {
$node->$field = $old_node->$field;
elseif (!isset($node->{$field})) {
$node->{$field} = $old_node->{$field};
}
}
}
@@ -289,7 +295,7 @@ class MigrateDestinationNode extends MigrateDestinationEntity {
// Potentially fix uid and timestamp in node_revisions.
$query = db_update('node_revision')
->condition('vid', $node->vid);
->condition('vid', $node->vid);
if (isset($changed)) {
$fields['timestamp'] = $changed;
}
@@ -319,7 +325,8 @@ class MigrateDestinationNode extends MigrateDestinationEntity {
/**
* Allows you to import revisions.
*
* Adapted from http://www.darrenmothersele.com/blog/2012/07/16/migrating-node-revisions-drupal-7/
* Adapted from
* http://www.darrenmothersele.com/blog/2012/07/16/migrating-node-revisions-drupal-7/
*
* Class MigrateDestinationNodeRevision
*
@@ -327,6 +334,7 @@ class MigrateDestinationNode extends MigrateDestinationEntity {
* @author cthos
*/
class MigrateDestinationNodeRevision extends MigrateDestinationNode {
/**
* Basic initialization.
*
@@ -398,9 +406,16 @@ class MigrateDestinationNodeRevision extends MigrateDestinationNode {
}
$this->completeRollback($vids);
foreach ($nids as $nid) {
$vid = db_select('node_revision', 'nr')->fields('nr', array('vid'))->condition('nid', $nid, '=')->execute()->fetchField();
$vid = db_select('node_revision', 'nr')
->fields('nr', array('vid'))
->condition('nid', $nid, '=')
->execute()
->fetchField();
if (!empty($vid)) {
db_update('node')->fields(array('vid' => $vid))->condition('nid', $nid, '=')->execute();
db_update('node')
->fields(array('vid' => $vid))
->condition('nid', $nid, '=')
->execute();
}
}
migrate_instrument_stop('revision_delete_multiple');

View File

@@ -6,6 +6,7 @@
*/
class MigratePathEntityHandler extends MigrateDestinationHandler {
public function __construct() {
$this->registerTypes(array('entity'));
}

View File

@@ -21,7 +21,8 @@
* public function prepareRow($row);
* $choices = Database::getConnection('default', 'legacy')
* ->select('src_poll_choice', 'c')
* ->fields('c', array('choice_label', 'choice_order', 'choice_total'))
* ->fields('c', array('choice_label', 'choice_order',
* 'choice_total'))
* ->condition('c.choiceid', $row->src_contentid);
* ->execute();
* $row->src_choices = array();
@@ -38,7 +39,8 @@
* ->select('src_poll_vote', 'v')
* ->fields('v', array('choice_uid', 'hostname', 'timestamp'))
* ->condition('v.choiceid', $row->src_contentid);
* $votes = $query->innerJoin('src_poll_choice', 'c', 'v.choice_id=c.choice_id')
* $votes = $query->innerJoin('src_poll_choice', 'c',
* 'v.choice_id=c.choice_id')
* ->fields('c', array('choice_label'))
* ->execute();
* $row->src_votes = array();
@@ -56,6 +58,7 @@
*/
class MigratePollEntityHandler extends MigrateDestinationHandler {
public function __construct() {
$this->registerTypes(array('node'));
}
@@ -92,7 +95,10 @@ class MigratePollEntityHandler extends MigrateDestinationHandler {
foreach ($row->choice as $choice) {
// Have no mapping tracking for chid, so assume choice text is unique.
db_update('poll_choice')
->fields(array('chvotes' => $choice['chvotes'], 'weight' => $choice['weight']))
->fields(array(
'chvotes' => $choice['chvotes'],
'weight' => $choice['weight'],
))
->condition('nid', $entity->nid)
->condition('chtext', $choice['chtext'])
->execute();
@@ -102,10 +108,10 @@ class MigratePollEntityHandler extends MigrateDestinationHandler {
foreach ($row->votes as $vote) {
if (!isset($vote['chid'])) {
$result = db_select('poll_choice', 'pc')
->fields('pc', array('chid'))
->condition('pc.nid', $entity->nid)
->condition('pc.chtext', $vote['chtext'])
->execute();
->fields('pc', array('chid'))
->condition('pc.nid', $entity->nid)
->condition('pc.chtext', $vote['chtext'])
->execute();
$chid = $result->fetchField();
}
else {

View File

@@ -6,6 +6,7 @@
*/
class MigrateStatisticsEntityHandler extends MigrateDestinationHandler {
public function __construct() {
$this->registerTypes(array('node'));
}

View File

@@ -10,6 +10,7 @@
* the Schema API.
*/
class MigrateDestinationTable extends MigrateDestination {
/**
* The schema of the current table.
*
@@ -81,6 +82,7 @@ class MigrateDestinationTable extends MigrateDestination {
* Object object to build. Prefilled with any fields mapped in the Migration.
* @param $row
* Raw source data object - passed through to prepare/complete handlers.
*
* @return array
* Array of key fields of the object that was saved if
* successful. FALSE on failure.
@@ -122,7 +124,7 @@ class MigrateDestinationTable extends MigrateDestination {
}
$select = db_select($this->tableName)
->fields($this->tableName);
->fields($this->tableName);
foreach ($this->schema['primary key'] as $key) {
$select->condition($key, $entity->{$key});
}
@@ -131,7 +133,7 @@ class MigrateDestinationTable extends MigrateDestination {
throw new MigrateException(t('System-of-record is DESTINATION, but the destination entity does not exist'));
}
foreach ($entity as $field => $value) {
$old_entity->$field = $entity->$field;
$old_entity->{$field} = $entity->{$field};
}
$entity = $old_entity;
}
@@ -159,6 +161,7 @@ class MigrateDestinationTable extends MigrateDestination {
*
* @param Migration $migration
* Optionally, the migration containing this destination.
*
* @return array
* Keys: machine names of the fields (to be passed to addFieldMapping)
* Values: Human-friendly descriptions of the fields.

View File

@@ -9,6 +9,7 @@
* Destination class implementing migration into a single table.
*/
class MigrateDestinationTableCopy extends MigrateDestination {
public function __construct($tableName, $keySchema) {
parent::__construct();
$this->tableName = $tableName;
@@ -41,6 +42,7 @@ class MigrateDestinationTableCopy extends MigrateDestination {
* Object object to build. Prefilled with any fields mapped in the Migration.
* @param $row
* Raw source data object - passed through to prepare/complete handlers.
*
* @return array
* Array of key fields of the object that was saved if
* successful. FALSE on failure.
@@ -53,15 +55,17 @@ class MigrateDestinationTableCopy extends MigrateDestination {
// table.
foreach ($fields as $field => $data) {
if (strpos($field, 'migrate_map_') === 0) {
unset($fields->$field);
unset($fields->{$field});
}
}
$keys = array_keys($this->keySchema);
$values = array();
$values = array();
foreach ($keys as $key) {
$values[] = $row->$key;
$values[] = $row->{$key};
}
$query = db_merge($this->tableName)->key($keys, $values)->fields((array)$fields);
$query = db_merge($this->tableName)
->key($keys, $values)
->fields((array) $fields);
try {
$status = $query->execute();
if ($status == MergeQuery::STATUS_INSERT) {
@@ -71,12 +75,10 @@ class MigrateDestinationTableCopy extends MigrateDestination {
$this->numUpdated++;
}
return $values;
}
catch (MigrateException $e) {
} catch (MigrateException $e) {
$migration->saveMessage($e->getMessage(), $e->getLevel());
Migration::displayMessage($e->getMessage());
}
catch (Exception $e) {
} catch (Exception $e) {
$migration->handleException($e);
}
}

View File

@@ -13,6 +13,7 @@
* Destination class implementing migration into terms.
*/
class MigrateDestinationTerm extends MigrateDestinationEntity {
/**
* Boolean indicating whether to permit duplicate terms to be created.
*
@@ -59,10 +60,12 @@ class MigrateDestinationTerm extends MigrateDestinationEntity {
}
/**
* Returns a list of fields available to be mapped for this vocabulary (bundle)
* Returns a list of fields available to be mapped for this vocabulary
* (bundle)
*
* @param Migration $migration
* Optionally, the migration containing this destination.
*
* @return array
* Keys: machine names of the fields (to be passed to addFieldMapping)
* Values: Human-friendly descriptions of the fields.
@@ -71,20 +74,20 @@ class MigrateDestinationTerm extends MigrateDestinationEntity {
$fields = array();
// First the core (taxonomy_term_data table) properties
$fields['tid'] = t('<a href="@doc">Existing term ID</a>',
array('@doc' => 'http://drupal.org/node/1349702#tid'));
array('@doc' => 'http://drupal.org/node/1349702#tid'));
$fields['name'] = t('<a href="@doc">Name</a>',
array('@doc' => 'http://drupal.org/node/1349702#name'));
array('@doc' => 'http://drupal.org/node/1349702#name'));
$fields['description'] = t('<a href="@doc">Description</a>',
array('@doc' => 'http://drupal.org/node/1349702#description'));
array('@doc' => 'http://drupal.org/node/1349702#description'));
$fields['parent'] = t('<a href="@doc">Parent (by Drupal term ID)</a>',
array('@doc' => 'http://drupal.org/node/1349702#parent'));
array('@doc' => 'http://drupal.org/node/1349702#parent'));
// TODO: Remove parent_name, implement via arguments
$fields['parent_name'] = t('<a href="@doc">Parent (by name)</a>',
array('@doc' => 'http://drupal.org/node/1349702#parent_name'));
array('@doc' => 'http://drupal.org/node/1349702#parent_name'));
$fields['format'] = t('<a href="@doc">Format</a>',
array('@doc' => 'http://drupal.org/node/1349702#format'));
array('@doc' => 'http://drupal.org/node/1349702#format'));
$fields['weight'] = t('<a href="@doc">Weight</a>',
array('@doc' => 'http://drupal.org/node/1349702#weight'));
array('@doc' => 'http://drupal.org/node/1349702#weight'));
// Then add in anything provided by handlers
$fields += migrate_handler_invoke_all('entity', 'fields', $this->entityType, $this->bundle, $migration);
@@ -131,6 +134,7 @@ class MigrateDestinationTerm extends MigrateDestinationEntity {
* Term object to build. Prefilled with any fields mapped in the Migration.
* @param $row
* Raw source data object - passed through to prepare/complete handlers.
*
* @return array
* Array of key fields (tid only in this case) of the term that was saved if
* successful. FALSE on failure.
@@ -142,7 +146,10 @@ class MigrateDestinationTerm extends MigrateDestinationEntity {
if (isset($term->tid)) {
if ($term->tid != $row->migrate_map_destid1) {
throw new MigrateException(t("Incoming tid !tid and map destination nid !destid1 don't match",
array('!tid' => $term->tid, '!destid1' => $row->migrate_map_destid1)));
array(
'!tid' => $term->tid,
'!destid1' => $row->migrate_map_destid1,
)));
}
}
else {
@@ -167,7 +174,7 @@ class MigrateDestinationTerm extends MigrateDestinationEntity {
array('!tid' => $term->tid)));
}
foreach ($rawterm as $field => $value) {
$old_term->$field = $term->$field;
$old_term->{$field} = $term->{$field};
}
$term = $old_term;
}
@@ -230,8 +237,8 @@ class MigrateDestinationTerm extends MigrateDestinationEntity {
if (!$this->allowDuplicateTerms && $existing_term = $this->findMatchingTerm($term)) {
foreach ($existing_term as $field => $value) {
if (!isset($term->$field)) {
$term->$field = $existing_term->$field;
if (!isset($term->{$field})) {
$term->{$field} = $existing_term->{$field};
}
}
}
@@ -243,8 +250,8 @@ class MigrateDestinationTerm extends MigrateDestinationEntity {
if ($existing_term) {
// Incoming data overrides existing data, so only copy non-existent fields
foreach ($existing_term as $field => $value) {
if (!isset($term->$field)) {
$term->$field = $existing_term->$field;
if (!isset($term->{$field})) {
$term->{$field} = $existing_term->{$field};
}
}
}

View File

@@ -13,6 +13,7 @@
* Destination class implementing migration into users.
*/
class MigrateDestinationUser extends MigrateDestinationEntity {
/**
* Indicates whether incoming passwords are md5-encrypted - if so, we will
* rehash them similarly to the D6->D7 upgrade path.
@@ -68,6 +69,7 @@ class MigrateDestinationUser extends MigrateDestinationEntity {
*
* @param Migration $migration
* Optionally, the migration containing this destination.
*
* @return array
* Keys: machine names of the fields (to be passed to addFieldMapping)
* Values: Human-friendly descriptions of the fields.
@@ -76,43 +78,43 @@ class MigrateDestinationUser extends MigrateDestinationEntity {
$fields = array();
// First the core (users table) properties
$fields['uid'] = t('<a href="@doc">Existing user ID</a>',
array('@doc' => 'http://drupal.org/node/1349632#uid'));
array('@doc' => 'http://drupal.org/node/1349632#uid'));
$fields['mail'] = t('<a href="@doc">Email address</a>',
array('@doc' => 'http://drupal.org/node/1349632#mail'));
array('@doc' => 'http://drupal.org/node/1349632#mail'));
$fields['name'] = t('<a href="@doc">Username</a>',
array('@doc' => 'http://drupal.org/node/1349632#name'));
array('@doc' => 'http://drupal.org/node/1349632#name'));
$fields['pass'] = t('<a href="@doc">Password</a>',
array('@doc' => 'http://drupal.org/node/1349632#pass'));
array('@doc' => 'http://drupal.org/node/1349632#pass'));
$fields['status'] = t('<a href="@doc">Status</a>',
array('@doc' => 'http://drupal.org/node/1349632#status'));
array('@doc' => 'http://drupal.org/node/1349632#status'));
$fields['created'] = t('<a href="@doc">Registered timestamp</a>',
array('@doc' => 'http://drupal.org/node/1349632#created'));
array('@doc' => 'http://drupal.org/node/1349632#created'));
$fields['access'] = t('<a href="@doc">Last access timestamp</a>',
array('@doc' => 'http://drupal.org/node/1349632#access'));
array('@doc' => 'http://drupal.org/node/1349632#access'));
$fields['login'] = t('<a href="@doc">Last login timestamp</a>',
array('@doc' => 'http://drupal.org/node/1349632#login'));
array('@doc' => 'http://drupal.org/node/1349632#login'));
$fields['roles'] = t('<a href="@doc">Role IDs</a>',
array('@doc' => 'http://drupal.org/node/1349632#roles'));
array('@doc' => 'http://drupal.org/node/1349632#roles'));
$fields['role_names'] = t('<a href="@doc">Role Names</a>',
array('@doc' => 'http://drupal.org/node/1349632#role_names'));
array('@doc' => 'http://drupal.org/node/1349632#role_names'));
$fields['picture'] = t('<a href="@doc">Picture</a>',
array('@doc' => 'http://drupal.org/node/1349632#picture'));
array('@doc' => 'http://drupal.org/node/1349632#picture'));
$fields['signature'] = t('<a href="@doc">Signature</a>',
array('@doc' => 'http://drupal.org/node/1349632#signature'));
array('@doc' => 'http://drupal.org/node/1349632#signature'));
$fields['signature_format'] = t('<a href="@doc">Signature format</a>',
array('@doc' => 'http://drupal.org/node/1349632#signature_format'));
array('@doc' => 'http://drupal.org/node/1349632#signature_format'));
$fields['timezone'] = t('<a href="@doc">Timezone</a>',
array('@doc' => 'http://drupal.org/node/1349632#timezone'));
array('@doc' => 'http://drupal.org/node/1349632#timezone'));
$fields['language'] = t('<a href="@doc">Language</a>',
array('@doc' => 'http://drupal.org/node/1349632#language'));
array('@doc' => 'http://drupal.org/node/1349632#language'));
$fields['theme'] = t('<a href="@doc">Default theme</a>',
array('@doc' => 'http://drupal.org/node/1349632#theme'));
array('@doc' => 'http://drupal.org/node/1349632#theme'));
$fields['init'] = t('<a href="@doc">Init</a>',
array('@doc' => 'http://drupal.org/node/1349632#init'));
array('@doc' => 'http://drupal.org/node/1349632#init'));
$fields['data'] = t('<a href="@doc">Data</a>',
array('@doc' => 'http://drupal.org/node/1349632#init'));
array('@doc' => 'http://drupal.org/node/1349632#init'));
$fields['is_new'] = t('Option: <a href="@doc">Indicates a new user with the specified uid should be created</a>',
array('@doc' => 'http://drupal.org/node/1349632#is_new'));
array('@doc' => 'http://drupal.org/node/1349632#is_new'));
// Then add in anything provided by handlers
$fields += migrate_handler_invoke_all('Entity', 'fields', $this->entityType, $this->bundle, $migration);
@@ -139,9 +141,11 @@ class MigrateDestinationUser extends MigrateDestinationEntity {
* Import a single user.
*
* @param $account
* Account object to build. Prefilled with any fields mapped in the Migration.
* Account object to build. Prefilled with any fields mapped in the
* Migration.
* @param $row
* Raw source data object - passed through to prepare/complete handlers.
*
* @return array
* Array of key fields (uid only in this case) of the user that was saved if
* successful. FALSE on failure.
@@ -155,7 +159,10 @@ class MigrateDestinationUser extends MigrateDestinationEntity {
if (isset($account->uid)) {
if ($account->uid != $row->migrate_map_destid1) {
throw new MigrateException(t("Incoming uid !uid and map destination uid !destid1 don't match",
array('!uid' => $account->uid, '!destid1' => $row->migrate_map_destid1)));
array(
'!uid' => $account->uid,
'!destid1' => $row->migrate_map_destid1,
)));
}
}
else {
@@ -195,7 +202,7 @@ class MigrateDestinationUser extends MigrateDestinationEntity {
}
$account->roles = drupal_map_assoc($account->roles);
}
if (empty($account->roles) && empty($old_account->roles)) {
if (empty($account->roles) && empty($old_account->roles)) {
$account->roles = array();
}
@@ -234,7 +241,7 @@ class MigrateDestinationUser extends MigrateDestinationEntity {
MigrateDestinationEntity::fieldAttachValidate('user', $account);
migrate_instrument_start('user_save');
$newaccount = user_save($old_account, (array)$account);
$newaccount = user_save($old_account, (array) $account);
migrate_instrument_stop('user_save');
if ($newaccount) {
if ($this->md5Passwords && !empty($account->pass)) {
@@ -285,6 +292,7 @@ class MigrateDestinationUser extends MigrateDestinationEntity {
}
class MigrateDestinationRole extends MigrateDestinationTable {
public function __construct() {
parent::__construct('role');
}
@@ -309,7 +317,7 @@ class MigrateDestinationRole extends MigrateDestinationTable {
public function rollback(array $id) {
migrate_instrument_start('role rollback');
$rid = reset($id);
user_role_delete((int)$rid);
user_role_delete((int) $rid);
migrate_instrument_stop('role rollback');
}
@@ -320,6 +328,7 @@ class MigrateDestinationRole extends MigrateDestinationTable {
* Object object to build. Prefilled with any fields mapped in the Migration.
* @param $row
* Raw source data object - passed through to prepare/complete handlers.
*
* @return array
* Array of key fields of the object that was saved if
* successful. FALSE on failure.
@@ -333,7 +342,10 @@ class MigrateDestinationRole extends MigrateDestinationTable {
if (isset($entity->rid)) {
if ($entity->rid != $row->migrate_map_destid1) {
throw new MigrateException(t("Incoming id !id and map destination id !destid don't match",
array('!id' => $entity->rid, '!destid' => $row->migrate_map_destid1)));
array(
'!id' => $entity->rid,
'!destid' => $row->migrate_map_destid1,
)));
}
}
else {
@@ -350,7 +362,7 @@ class MigrateDestinationRole extends MigrateDestinationTable {
$old_entity = user_role_load($entity->rid);
foreach ($entity as $field => $value) {
$old_entity->$field = $entity->$field;
$old_entity->{$field} = $entity->{$field};
}
$entity = $old_entity;
}

View File

@@ -36,6 +36,7 @@ class MigrateDestinationVariable extends MigrateDestination {
*
* @param Migration $migration
* Optionally, the migration containing this destination.
*
* @return array
* Keys: machine names of the fields (to be passed to addFieldMapping)
* Values: Human-friendly descriptions of the fields.
@@ -52,9 +53,11 @@ class MigrateDestinationVariable extends MigrateDestination {
* Import a single row.
*
* @param $variable
* Variable object to build. Prefilled with any fields mapped in the Migration.
* Variable object to build. Prefilled with any fields mapped in the
* Migration.
* @param $row
* Raw source data object - passed through to prepare/complete handlers.
*
* @return array
* Array of key fields of the object that was saved if
* successful. FALSE on failure.

View File

@@ -5,6 +5,213 @@
* Define a MigrateSource for importing from comma separated values files.
*/
/**
* Implementation of MigrateList, for retrieving a list of IDs to be migrated
* from a CSV file.
*/
class MigrateListCSV extends MigrateList {
/**
* The path to the CSV file containing a list of IDs to be processed.
*
* @var string
*/
protected $file;
/**
* File handle for the CSV file being iterated.
*
* @var resource
*/
protected $csvHandle = NULL;
/**
* The column which contains the ID.
*
* If numeric, this is the index of the column from 0; if non-numeric, this
* is the column name as given by the header row.
*/
protected $idColumn;
/**
* The number of rows in the CSV file before the data starts.
*
* @var integer
*/
protected $headerRows = 0;
/**
* The array keys taken from the first row.
*
* @var array
*/
protected $headers = array();
/**
* Parameters for the fgetcsv() call.
*
* @var array
*/
protected $fgetcsv = array();
/**
* Constructor for MigrateListCSV.
*
* @param $list_path
* The path to the CSV file that holds the list of IDs.
* @param $id_column
* The column in the file that holds the IDs. A numeric index for the column,
* from 0.
* @param $options = array()
* An array of further options for the CSV file.
*/
public function __construct($list_path, $id_column, $options = array()) {
parent::__construct();
$this->file = $list_path;
$this->idColumn = $id_column;
$this->options = $options;
// fgetcsv specific options
foreach (array(
'length' => NULL,
'delimiter' => ',',
'enclosure' => '"',
'escape' => '\\',
) as $key => $default) {
$this->fgetcsv[$key] = isset($options[$key]) ? $options[$key] : $default;
}
if (!empty($options['header_rows'])) {
$this->headerRows = $options['header_rows'];
}
else {
$this->headerRows = 0;
}
if (!is_numeric($id_column)) {
//we need to store the headers.
$this->csvHandle = fopen($this->file, 'r');
if (!$this->validResource()) {
return;
}
$this->headers = $this->getNextLine();
fclose($this->csvHandle);
$this->csvHandle = NULL;
}
}
/**
* Return a string representing the source file.
*
* @return string
*/
public function __toString() {
return $this->file;
}
/**
* Return an array of IDs from the CSV file.
*
* @return array
*/
public function getIdList() {
$ids = array();
$this->csvHandle = fopen($this->file, 'r');
if (!$this->validResource()) {
return $ids;
}
// Skip the headers if any,
for ($i = 0; $i < $this->headerRows; $i++) {
$this->getNextLine();
}
while ($row = $this->getNextLine()) {
$ids[] = $row[$this->idColumn];
}
fclose($this->csvHandle);
$this->csvHandle = NULL;
return $ids;
}
/**
* Return a count of all available IDs from the source listing.
*
* @return integer
*/
public function computeCount() {
// If the data may have embedded newlines, the file line count won't reflect
// the number of CSV records (one record will span multiple lines). We need
// to scan with fgetcsv to get the true count.
if (!empty($this->options['embedded_newlines'])) {
$this->csvHandle = fopen($this->file, 'r');
$count = 0;
if (!$this->validResource()) {
return $count;
}
// Skip all but the last header
for ($i = 0; $i < $this->headerRows; $i++) {
fgets($this->csvHandle);
}
while ($this->getNextLine()) {
$count++;
}
fclose($this->csvHandle);
$this->csvHandle = NULL;
}
else {
$file = new SplFileObject($this->file, 'r');
$file->seek(PHP_INT_MAX);
$count = $file->key() + 1;
$file->rewind();
$count -= $this->headerRows;
}
return $count;
}
/**
* Get the next line of the CSV file.
* Returns an array of the next line, keyed by headers if required
*
* @return array
*/
protected function getNextLine() {
// escape parameter was added in PHP 5.3.
if (version_compare(phpversion(), '5.3', '<')) {
$row = fgetcsv($this->csvHandle, $this->fgetcsv['length'],
$this->fgetcsv['delimiter'], $this->fgetcsv['enclosure']);
}
else {
$row = fgetcsv($this->csvHandle, $this->fgetcsv['length'],
$this->fgetcsv['delimiter'], $this->fgetcsv['enclosure'],
$this->fgetcsv['escape']);
}
// Key the array with the headers
if (!empty($this->headers) && $row) {
$row = array_combine($this->headers, $row);
}
return $row;
}
/**
* Check if resource loaded correctly.
*
* @return bool
*/
public function validResource() {
if (!$this->csvHandle) {
Migration::displayMessage(t('Could not open CSV file !url',
array('!url' => $this->file)));
}
return (bool) $this->csvHandle;
}
}
/**
* Implementation of MigrateSource, to handle imports from CSV files.
*
@@ -12,6 +219,7 @@
* UTF BOM (Byte Order Marker) so they are interpreted correctly.
*/
class MigrateSourceCSV extends MigrateSource {
/**
* List of available source fields.
*
@@ -47,6 +255,13 @@ class MigrateSourceCSV extends MigrateSource {
*/
protected $rowNumber;
/**
* The path to the source file.
*
* @var string
*/
protected $file;
/**
* Simple initialization.
*
@@ -73,7 +288,12 @@ class MigrateSourceCSV extends MigrateSource {
$this->options = $options;
$this->fields = $fields;
// fgetcsv specific options
foreach (array('length' => NULL, 'delimiter' => ',', 'enclosure' => '"', 'escape' => '\\') as $key => $default) {
foreach (array(
'length' => NULL,
'delimiter' => ',',
'enclosure' => '"',
'escape' => '\\',
) as $key => $default) {
$this->fgetcsv[$key] = isset($options[$key]) ? $options[$key] : $default;
}
// One can either pass in an explicit list of column names to use, or if we have
@@ -81,6 +301,9 @@ class MigrateSourceCSV extends MigrateSource {
if ($this->headerRows && empty($csvcolumns)) {
$this->csvcolumns = array();
$this->csvHandle = fopen($this->file, 'r');
if (!$this->validResource()) {
return;
}
// Skip all but the last header
for ($i = 0; $i < $this->headerRows - 1; $i++) {
$this->getNextLine();
@@ -139,11 +362,14 @@ class MigrateSourceCSV extends MigrateSource {
// to scan with fgetcsv to get the true count.
if (!empty($this->options['embedded_newlines'])) {
$this->csvHandle = fopen($this->file, 'r');
$count = 0;
if (!$this->validResource()) {
return $count;
}
// Skip all but the last header
for ($i = 0; $i < $this->headerRows; $i++) {
fgets($this->csvHandle);
}
$count = 0;
while ($this->getNextLine()) {
$count++;
}
@@ -171,6 +397,9 @@ class MigrateSourceCSV extends MigrateSource {
}
// Load up the first row, skipping the header(s) if necessary
$this->csvHandle = fopen($this->file, 'r');
if (!$this->validResource()) {
return;
}
for ($i = 0; $i < $this->headerRows; $i++) {
$this->getNextLine();
}
@@ -196,7 +425,7 @@ class MigrateSourceCSV extends MigrateSource {
unset($row[$int]);
}
$row['csvrownum'] = $this->rowNumber++;
return (object)$row;
return (object) $row;
}
else {
fclose($this->csvHandle);
@@ -218,4 +447,18 @@ class MigrateSourceCSV extends MigrateSource {
}
return $row;
}
/**
* Check if resource loaded correctly.
*
* @return bool
*/
public function validResource() {
if (!$this->csvHandle) {
Migration::displayMessage(t('Could not open CSV file !url',
array('!url' => $this->file)));
}
return (bool) $this->csvHandle;
}
}

View File

@@ -9,6 +9,7 @@
* Implementation of MigrateSource, to handle imports from remote DB2 servers.
*/
class MigrateSourceDB2 extends MigrateSource {
/**
* Array containing information for connecting to DB2:
* database - Database to connect to
@@ -25,6 +26,7 @@ class MigrateSourceDB2 extends MigrateSource {
* @var resource
*/
protected $connection;
public function getConnection() {
return $this->connection;
}
@@ -54,7 +56,7 @@ class MigrateSourceDB2 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;

View File

@@ -23,15 +23,71 @@ define('MIGRATE_CHUNK_SEPARATOR', '-?MIGRATECHUNK?-');
* count, and then retrieve each chunk by it's ID.
*/
abstract class MigrateContentParser {
/**
* Tells the MigrateListFiles implementation to always use chunk IDs when
* constructing item IDs.
*/
public $alwaysUseChunkIDs = FALSE;
/**
* The content of the current file to parse.
*/
protected $content;
public function setContent($content) {
/**
* The ID of the current file being parsed.
*/
protected $item_id;
/**
* Set the content and file ID for the current file to parse.
*
* @param $content
* The content of the current file to parse.
* @param $item_id = NULL
* The ID of the file. The chunk IDs are appended to this to form the IDs
* that are returned by the MigrateList implementation.
*/
public function setContent($content, $item_id = NULL) {
$this->content = $content;
$this->item_id = $item_id;
}
/**
* Return the list of IDs for all the chunks found in the current file.
*
* Unless $alwaysUseChunkIDs is set to TRUE, this is only called if
* getChunkCount() returned a count greater than 1.
*
*
* @return
* An array of IDs.
*/
abstract public function getChunkIDs();
/**
* Get a single chunk from the current file.
*
* @param $id
* The ID for the chunk. This is one of the IDs returned by getChunkIDs().
*
* @return
* The content of the chunk.
*/
abstract public function getChunk($id);
/**
* Return the count of chunks in the current file.
*
* If this returns 1, then getChunkIDs() is not called and the file is treated
* as a single chunk. To override this, set $alwaysUseChunkIDs to TRUE.
*
* @return int
* The number of chunks in the current file.
*/
abstract public function getChunkCount();
}
/**
@@ -40,12 +96,15 @@ abstract class MigrateContentParser {
* primarily for when your HTML files map one-to-one to nodes.
*/
class MigrateSimpleContentParser extends MigrateContentParser {
public function getChunkIDs() {
return array('1');
}
public function getChunk($id) {
return $this->content;
}
public function getChunkCount() {
return 1;
}
@@ -54,14 +113,22 @@ class MigrateSimpleContentParser extends MigrateContentParser {
/**
* Implementation of MigrateList, for retrieving a list of IDs to be migrated
* from a directory listing. Each item is a file, it's ID is the path.
*
* If individual files contain more than one source, use a MigrateContentParser
* to parse the file and split it into chunks.
*/
class MigrateListFiles extends MigrateList {
protected $listDirs;
protected $baseDir;
protected $fileMask;
protected $directoryOptions;
protected $parser;
protected $getContents;
/**
@@ -77,22 +144,25 @@ class MigrateListFiles extends MigrateList {
* );
* @param $base_dir
* The base dir is the part of the path that will be excluded when making
* an ID for each file. To continue the example from above, you want base_dir
* to be = '/var/html_source', so that the files will have IDs in the format
* an ID for each file. To continue the example from above, you want
* base_dir to be = '/var/html_source', so that the files will have IDs in
* the format
* '/en/news/news_2011_03_4.html'.
* @param $file_mask
* Passed on and used to filter for certain types of files. Use a regular
* expression, for example '/(.*\.htm$|.*\.html$)/i' to match all .htm and
* .html files, case insensitive.
* (optional) Passed on and used to filter for certain types of files. Use
* a
* regular expression, for example '/(.*\.htm$|.*\.html$)/i' to match all
* .htm and .html files, case insensitive. Defaults to matching all files.
* @param $options
* Options that will be passed on to file_scan_directory(). See docs of that
* Options that will be passed on to file_scan_directory(). See docs of
* that
* core Drupal function for more information.
* @param MigrateContentParser $parser
* Content parser class to use.
* @param $get_contents
* Whether to load the contents of files.
*/
public function __construct($list_dirs, $base_dir, $file_mask = NULL, $options = array(), MigrateContentParser $parser = NULL, $get_contents = TRUE) {
public function __construct($list_dirs, $base_dir, $file_mask = '//', $options = array(), MigrateContentParser $parser = NULL, $get_contents = TRUE) {
if (!$parser) {
$parser = new MigrateSimpleContentParser();
}
@@ -142,20 +212,21 @@ class MigrateListFiles extends MigrateList {
protected function getIDsFromFiles(array $files) {
$ids = array();
foreach ($files as $file) {
$file_base_id = str_replace($this->baseDir, '', (string) $file->uri);
if ($this->getContents) {
$contents = file_get_contents($file->uri);
$this->parser->setContent($contents);
if ($this->parser->getChunkCount() > 1) {
$this->parser->setContent($contents, $file_base_id);
if ($this->parser->alwaysUseChunkIDs || $this->parser->getChunkCount() > 1) {
foreach ($this->parser->getChunkIDs() as $chunk_id) {
$ids[] = str_replace($this->baseDir, '', (string) $file->uri) . MIGRATE_CHUNK_SEPARATOR . $chunk_id;
$ids[] = $file_base_id . MIGRATE_CHUNK_SEPARATOR . $chunk_id;
}
}
else {
$ids[] = str_replace($this->baseDir, '', (string) $file->uri);
$ids[] = $file_base_id;
}
}
else {
$ids[] = str_replace($this->baseDir, '', (string) $file->uri);
$ids[] = $file_base_id;
}
}
@@ -183,7 +254,9 @@ class MigrateListFiles extends MigrateList {
class MigrateItemFile extends MigrateItem {
protected $baseDir;
protected $getContents;
protected $parser;
/**
@@ -215,28 +288,30 @@ class MigrateItemFile extends MigrateItem {
* The item object for migration.
*/
public function getItem($id) {
$pieces = explode(MIGRATE_CHUNK_SEPARATOR ,$id);
$pieces = explode(MIGRATE_CHUNK_SEPARATOR, $id);
$item_uri = $this->baseDir . $pieces[0];
$chunk = !empty($pieces[1]) ? $pieces[1] : '';
// Get the file data at the specified URI
$data = $this->loadFile($item_uri);
if (is_string($data)) {
$this->parser->setContent($data);
$this->parser->setContent($data, $pieces[0]);
$return = new stdClass;
$return->filedata = $this->parser->getChunk($chunk);
return $return;
}
else if ($data === TRUE) {
$return = new stdClass;
return $return;
}
else {
$migration = Migration::currentMigration();
$message = t('Loading of !objecturi failed:', array('!objecturi' => $item_uri));
$migration->getMap()->saveMessage(
array($id), $message, MigrationBase::MESSAGE_ERROR);
return NULL;
if ($data === TRUE) {
$return = new stdClass;
return $return;
}
else {
$migration = Migration::currentMigration();
$message = t('Loading of !objecturi failed:', array('!objecturi' => $item_uri));
$migration->getMap()->saveMessage(
array($id), $message, MigrationBase::MESSAGE_ERROR);
return NULL;
}
}
}

View File

@@ -10,6 +10,7 @@
* from a JSON object.
*/
class MigrateListJSON extends MigrateList {
/**
* A URL pointing to an JSON object containing a list of IDs to be processed.
*
@@ -35,7 +36,8 @@ class MigrateListJSON extends MigrateList {
}
/**
* Load the JSON at the given URL, and return an array of the IDs found within it.
* Load the JSON at the given URL, and return an array of the IDs found
* within it.
*
* @return array
*/
@@ -51,12 +53,12 @@ class MigrateListJSON extends MigrateList {
migrate_instrument_stop("Retrieve $this->listUrl");
if ($json) {
$data = drupal_json_decode($json);
if ($data) {
if ($data !== NULL) {
return $this->getIDsFromJSON($data);
}
}
Migration::displayMessage(t('Loading of !listurl failed:',
array('!listurl' => $this->listUrl)));
array('!listurl' => $this->listUrl)));
return NULL;
}
@@ -104,6 +106,7 @@ class MigrateListJSON extends MigrateList {
* an ID provided by a MigrateList class.
*/
class MigrateItemJSON extends MigrateItem {
/**
* A URL pointing to a JSON object containing the data for one item to be
* migrated.
@@ -136,7 +139,7 @@ class MigrateItemJSON extends MigrateItem {
}
else {
$migration = Migration::currentMigration();
$message = t('Loading of !objecturl failed:', array('!objecturl' => $item_url));
$message = t('Loading of !objecturl failed:', array('!objecturl' => $item_url));
$migration->getMap()->saveMessage(
array($id), $message, MigrationBase::MESSAGE_ERROR);
return NULL;
@@ -178,6 +181,7 @@ class MigrateItemJSON extends MigrateItem {
* To deal with different structures, extend this class and override next().
*/
class MigrateJSONReader implements Iterator {
/**
* URL of the source JSON file.
*
@@ -242,7 +246,8 @@ class MigrateJSONReader implements Iterator {
* The next non-whitespace character, or FALSE on end-of-file.
*/
protected function getNonBlank() {
while (($c = fgetc($this->fileHandle)) !== FALSE && trim($c) == '') {}
while (($c = fgetc($this->fileHandle)) !== FALSE && trim($c) == '') {
}
return $c;
}
@@ -266,7 +271,7 @@ class MigrateJSONReader implements Iterator {
$this->fileHandle = fopen($this->url, 'r');
if (!$this->fileHandle) {
Migration::displayMessage(t('Could not open JSON file !url',
array('!url' => $this->url)));
array('!url' => $this->url)));
return;
}
@@ -278,7 +283,7 @@ class MigrateJSONReader implements Iterator {
}
if ($char != '[') {
Migration::displayMessage(t('!url is not a JSON file containing an array of objects',
array('!url' => $this->url)));
array('!url' => $this->url)));
return;
}
}
@@ -390,9 +395,11 @@ class MigrateJSONReader implements Iterator {
}
/**
* Implementation of MigrateSource, to handle imports from stand-alone JSON files.
* Implementation of MigrateSource, to handle imports from stand-alone JSON
* files.
*/
class MigrateSourceJSON extends MigrateSource {
/**
* The MigrateJSONReader object serving as a cursor over the JSON source file.
*
@@ -402,6 +409,7 @@ class MigrateSourceJSON extends MigrateSource {
/**
* Name of the field within the JSON object holding the ID value.
*
* @var string
*/
protected $idField;
@@ -454,7 +462,7 @@ class MigrateSourceJSON extends MigrateSource {
* MigrateJSONReader).
*/
public function __construct($urls, $id_field, array $fields = array(),
array $options = array()) {
array $options = array()) {
parent::__construct($options);
$this->idField = $id_field;
if (empty($options['reader_class'])) {
@@ -581,7 +589,7 @@ class MigrateSourceJSON extends MigrateSource {
// Return value
$status = FALSE;
while ($this->activeUrl === NULL || (count($this->sourceUrls)-1) > $this->activeUrl) {
while ($this->activeUrl === NULL || (count($this->sourceUrls) - 1) > $this->activeUrl) {
if (is_null($this->activeUrl)) {
$this->activeUrl = 0;
}

View File

@@ -15,7 +15,9 @@
* obtain a list of IDs from an XML document).
*/
abstract class MigrateList {
public function __construct() {}
public function __construct() {
}
/**
* Implementors are expected to return a string representing where the listing
@@ -34,7 +36,8 @@ abstract class MigrateList {
abstract public function getIdList();
/**
* Implementors are expected to return a count of IDs available to be migrated.
* Implementors are expected to return a count of IDs available to be
* migrated.
*
* @return int
*/
@@ -46,7 +49,9 @@ abstract class MigrateList {
* given migratable item given its ID as provided by the MigrateList class.
*/
abstract class MigrateItem {
public function __construct() {}
public function __construct() {
}
/**
* Implementors are expected to return an object representing a source item.
@@ -74,6 +79,7 @@ abstract class MigrateItem {
* IDs provided by a MigrateList and retrieving data from a MigrateItem.
*/
class MigrateSourceList extends MigrateSource {
/**
* MigrateList object used to obtain ID lists.
*
@@ -105,8 +111,7 @@ class MigrateSourceList extends MigrateSource {
/**
* Simple initialization.
*/
public function __construct(MigrateList $list_class, MigrateItem $item_class, $fields = array(),
$options = array()) {
public function __construct(MigrateList $list_class, MigrateItem $item_class, $fields = array(), $options = array()) {
parent::__construct($options);
$this->listClass = $list_class;
$this->itemClass = $item_class;
@@ -122,6 +127,15 @@ class MigrateSourceList extends MigrateSource {
return (string) $this->listClass;
}
/**
* Return MigrateList object used to obtain ID lists.
*
* @return MigrateList
*/
public function listClass() {
return $this->listClass;
}
/**
* Returns a list of fields available to be mapped from the source query.
* Since we can't reliably figure out what "fields" are in the source,
@@ -195,8 +209,9 @@ class MigrateSourceList extends MigrateSource {
foreach (array_keys($this->activeMap->getSourceKey()) as $key_name) {
// Grab the first id and advance the array cursor. Then save the ID
// using the map source key - it will be used for mapping.
list(, $id) = each($ids);
$row->$key_name = $id;
$id = current($ids);
next($ids);
$row->{$key_name} = $id;
}
break;
}

View File

@@ -9,6 +9,7 @@
* Implementation of MigrateSource, to handle imports from MongoDB connections.
*/
class MigrateSourceMongoDB extends MigrateSource {
/**
* The mongodb collection object.
*
@@ -41,8 +42,8 @@ class MigrateSourceMongoDB extends MigrateSource {
* Simple initialization.
*/
public function __construct(MongoCollection $collection, array $query,
array $fields = array(), array $sort = array('_id' => 1),
array $options = array()) {
array $fields = array(), array $sort = array('_id' => 1),
array $options = array()) {
parent::__construct($options);
$this->collection = $collection;
@@ -106,8 +107,8 @@ class MigrateSourceMongoDB extends MigrateSource {
migrate_instrument_start('MigrateSourceMongoDB execute');
try {
$this->cursor = $this->collection
->find($this->query)
->sort($this->sort);
->find($this->query)
->sort($this->sort);
$this->cursor->timeout(-1);
} catch (MongoCursorException $e) {
Migration::displayMessage($e->getMessage(), 'error');
@@ -123,20 +124,20 @@ class MigrateSourceMongoDB extends MigrateSource {
public function __toString() {
if (is_null($this->cursor)) {
$this->cursor = $this->collection
->find($this->query)
->sort($this->sort);
->find($this->query)
->sort($this->sort);
$this->cursor->timeout(-1);
}
$query_info = $this->cursor->info();
$query = 'query: ' . drupal_json_encode($query_info['query']['$query']);
$sort = 'order by: ' . drupal_json_encode($query_info['query']['$orderby']);
$query = 'query: ' . drupal_json_encode($query_info['query']['$query']);
$sort = 'order by: ' . drupal_json_encode($query_info['query']['$orderby']);
$fields = 'fields: ' . drupal_json_encode($query_info['fields']);
return $query . PHP_EOL .
$sort . PHP_EOL .
$fields . PHP_EOL;
$sort . PHP_EOL .
$fields . PHP_EOL;
}
/**
@@ -147,13 +148,14 @@ class MigrateSourceMongoDB extends MigrateSource {
* Document key value.
* @param array $keys
* List of keys.
*
* @return type
*/
public function getMongoId($document_id, $keys) {
if ($keys[0]['name'] != '_id') {
switch ($keys[0]['type']) {
case 'int':
return (int)$document_id;
return (int) $document_id;
break;
default:
return $document_id;

View File

@@ -6,9 +6,11 @@
*/
/**
* 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
@@ -62,7 +64,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;

View File

@@ -14,7 +14,9 @@
* to obtain the data for a given migratable item given its ID.
*/
abstract class MigrateItems {
public function __construct() {}
public function __construct() {
}
/**
* Implementors are expected to return a string representing where the listing
@@ -33,7 +35,8 @@ abstract class MigrateItems {
abstract public function getIdList();
/**
* Implementors are expected to return a count of IDs available to be migrated.
* Implementors are expected to return a count of IDs available to be
* migrated.
*
* @return int
*/
@@ -70,6 +73,7 @@ abstract class MigrateItems {
* IDs provided by a MigrateItems and retrieving data from a MigrateItems.
*/
class MigrateSourceMultiItems extends MigrateSource {
/**
* MigrateItems object used to obtain the list of IDs and source for
* all objects.
@@ -137,7 +141,7 @@ class MigrateSourceMultiItems extends MigrateSource {
* @return int
*/
public function computeCount() {
// @API: Support old count method for now.
// @API: Support old count method for now.
if (method_exists($this->itemsClass, 'computeCount')) {
return $this->itemsClass->computeCount();
}
@@ -156,8 +160,8 @@ class MigrateSourceMultiItems extends MigrateSource {
if ($this->idList) {
$this->idsToProcess = $this->idList;
}
else {
$this->idsToProcess = $this->itemsClass->getIdList();
elseif (!$this->idsToProcess = $this->itemsClass->getIdList()) {
$this->idsToProcess = array();
}
$this->idIterator = ($this->idsToProcess instanceof Iterator) ?
$this->idsToProcess : new ArrayIterator($this->idsToProcess);
@@ -186,7 +190,7 @@ class MigrateSourceMultiItems extends MigrateSource {
// Save the ID using the map source key - it will be used for mapping
$sourceKey = $this->activeMap->getSourceKey();
$key_name = key($sourceKey);
$row->$key_name = $id;
$row->{$key_name} = $id;
break;
}
}

View File

@@ -6,14 +6,17 @@
*/
/**
* Implementation of MigrateSource, to handle imports from remote Oracle servers.
* Implementation of MigrateSource, to handle imports from remote Oracle
* servers.
*/
class MigrateSourceOracle extends MigrateSource {
/**
* Array containing information for connecting to Oracle:
* username - Username to connect as
* password - Password for logging in
* connection_string - See http://us.php.net/manual/en/function.oci-connect.php.
* connection_string - See
* http://us.php.net/manual/en/function.oci-connect.php.
*
* @var array
*/
@@ -25,6 +28,7 @@ class MigrateSourceOracle extends MigrateSource {
* @var resource
*/
protected $connection;
public function getConnection() {
return $this->connection;
}
@@ -63,7 +67,7 @@ class MigrateSourceOracle 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;
@@ -206,13 +210,13 @@ class MigrateSourceOracle extends MigrateSource {
* Implementation of MigrateSource::getNextRow().
*
* Returns the next row of the result set as an object, making sure NULLs are
* represented as PHP NULLs and that LOBs are returned directly without special
* handling.
* represented as PHP NULLs and that LOBs are returned directly without
* special handling.
*/
public function getNextRow() {
$row = oci_fetch_array($this->result, OCI_ASSOC | OCI_RETURN_NULLS | OCI_RETURN_LOBS);
if (!empty($row)) {
return (object)$row;
return (object) $row;
}
else {
return FALSE;

View File

@@ -17,6 +17,7 @@
* Implements MigrateSource, to handle imports from XLS files.
*/
class MigrateSourceSpreadsheet extends MigrateSource {
/**
* PHPExcel object for storing the workbook data.
*
@@ -62,7 +63,8 @@ class MigrateSourceSpreadsheet extends MigrateSource {
/**
* The current row number in the XLS file.
*
* @var integer+ */
* @var integer+
*/
protected $rowNumber;
/**
@@ -70,6 +72,13 @@ class MigrateSourceSpreadsheet extends MigrateSource {
*/
protected $columns;
/**
* The first row from where the table starts. It's a "zero based" value.
*
* @var int
*/
protected $headerRows = 0;
/**
* Simple initialization.
*
@@ -78,13 +87,18 @@ class MigrateSourceSpreadsheet extends MigrateSource {
* @param string $sheet_name
* The name of the sheet to be processed.
* @param array $options
* Options applied to this source.
* Options applied to this source. If the source data begins on different
* row than the first row, pass this "zero based" value as 'header_rows' in
* options, along with other options inherited from MigrateSource.
*/
public function __construct($path, $sheet_name, $columns = array(), array $options = array()) {
parent::__construct($options);
$this->file = $path;
$this->sheetName = $sheet_name;
$this->columns = $columns;
if (!empty($options['header_rows'])) {
$this->headerRows = $options['header_rows'];
}
// Load the workbook.
if ($this->load()) {
@@ -94,7 +108,8 @@ class MigrateSourceSpreadsheet extends MigrateSource {
// Map field names to their column index.
for ($col = 0; $col < $this->cols; ++$col) {
$this->fields[$col] = trim($this->worksheet->getCellByColumnAndRow($col, 1)->getValue());
$this->fields[$col] = trim($this->worksheet->getCellByColumnAndRow($col, $this->headerRows + 1)
->getValue());
}
$this->unload();
@@ -143,8 +158,7 @@ class MigrateSourceSpreadsheet extends MigrateSource {
// Load the source file.
$this->workbook = $reader->load($this->file);
$this->worksheet = $this->workbook->getSheet();
}
catch (Exception $e) {
} catch (Exception $e) {
Migration::displayMessage(t('Error loading file: %message', array('%message' => $e->getMessage())));
return FALSE;
}
@@ -190,8 +204,8 @@ class MigrateSourceSpreadsheet extends MigrateSource {
* Returns a count of all available source records.
*/
public function computeCount() {
// Subtract 1 for the header.
return $this->rows - 1;
// Subtract the non-data rows (rows before header and the header).
return $this->rows - $this->headerRows - 1;
}
/**
@@ -205,7 +219,7 @@ class MigrateSourceSpreadsheet extends MigrateSource {
$this->load();
}
$this->rowNumber = 1;
$this->rowNumber = $this->headerRows + 1;
}
/**
@@ -221,8 +235,9 @@ class MigrateSourceSpreadsheet extends MigrateSource {
$row_values = array();
for ($col = 0; $col < $this->cols; ++$col) {
if (in_array($this->fields[$col], $this->columns) || empty($this->columns)) {
$row_values[$this->fields[$col]] = trim($this->worksheet->getCellByColumnAndRow($col, $this->rowNumber)->getValue());
}
$row_values[$this->fields[$col]] = trim($this->worksheet->getCellByColumnAndRow($col, $this->rowNumber)
->getValue());
}
}
return (object) $row_values;

View File

@@ -9,6 +9,7 @@
* Implementation of MigrateSource, to handle imports from Drupal connections.
*/
class MigrateSourceSQL extends MigrateSource {
/**
* The SQL query objects from which to obtain data, and counts of data
*
@@ -72,6 +73,7 @@ class MigrateSourceSQL extends MigrateSource {
* @var boolean
*/
protected $mapJoinable = FALSE;
// Dynamically set whether the map is joinable - not really for production use,
// this is primarily to support simpletests
public function setMapJoinable($map_joinable) {
@@ -97,7 +99,8 @@ class MigrateSourceSQL extends MigrateSource {
* Return an options array for PDO sources.
*
* @param boolean $map_joinable
* Indicates whether the map table can be joined directly to the source query.
* Indicates whether the map table can be joined directly to the source
* query.
* @param boolean $cache_counts
* Indicates whether to cache counts of source records.
*/
@@ -121,7 +124,7 @@ class MigrateSourceSQL extends MigrateSource {
* Options applied to this source.
*/
public function __construct(SelectQueryInterface $query, array $fields = array(),
SelectQueryInterface $count_query = NULL, array $options = array()) {
SelectQueryInterface $count_query = NULL, array $options = array()) {
parent::__construct($options);
$this->originalQuery = $query;
$this->query = clone $query;
@@ -153,30 +156,30 @@ class MigrateSourceSQL extends MigrateSource {
// directly to the query, but this won't work unless/until
// http://drupal.org/node/802514 is committed, assume joinable for now
$this->mapJoinable = TRUE;
/* // To be able to join the map directly, it must be a PDO map on the same
// connection, or a compatible connection
$map = $migration->getMap();
if (is_a($map, 'MigrateSQLMap')) {
$map_options = $map->getConnection()->getConnectionOptions();
$query_options = $this->query->connection()->getConnectionOptions();
/* // To be able to join the map directly, it must be a PDO map on the same
// connection, or a compatible connection
$map = $migration->getMap();
if (is_a($map, 'MigrateSQLMap')) {
$map_options = $map->getConnection()->getConnectionOptions();
$query_options = $this->query->connection()->getConnectionOptions();
// Identical options means it will work
if ($map_options == $query_options) {
$this->mapJoinable = TRUE;
}
else {
// Otherwise, the one scenario we know will work is if it's MySQL and
// the credentials match (SQLite too?)
if ($map_options['driver'] == 'mysql' && $query_options['driver'] == 'mysql') {
if ($map_options['host'] == $query_options['host'] &&
$map_options['port'] == $query_options['port'] &&
$map_options['username'] == $query_options['username'] &&
$map_options['password'] == $query_options['password']) {
$this->mapJoinable = TRUE;
}
}
}
}*/
// Identical options means it will work
if ($map_options == $query_options) {
$this->mapJoinable = TRUE;
}
else {
// Otherwise, the one scenario we know will work is if it's MySQL and
// the credentials match (SQLite too?)
if ($map_options['driver'] == 'mysql' && $query_options['driver'] == 'mysql') {
if ($map_options['host'] == $query_options['host'] &&
$map_options['port'] == $query_options['port'] &&
$map_options['username'] == $query_options['username'] &&
$map_options['password'] == $query_options['password']) {
$this->mapJoinable = TRUE;
}
}
}
}*/
}
}
@@ -220,26 +223,26 @@ class MigrateSourceSQL extends MigrateSource {
}
}
/*
* Handle queries without explicit field lists
* TODO: Waiting on http://drupal.org/node/814312
$info = Database::getConnectionInfo($query->getConnection());
$database = $info['default']['database'];
foreach ($this->query->getTables() as $table) {
if (isset($table['all_fields']) && $table['all_fields']) {
/*
* Handle queries without explicit field lists
* TODO: Waiting on http://drupal.org/node/814312
$info = Database::getConnectionInfo($query->getConnection());
$database = $info['default']['database'];
foreach ($this->query->getTables() as $table) {
if (isset($table['all_fields']) && $table['all_fields']) {
$database = 'plants';
$table = $table['table'];
$sql = 'SELECT column_name
FROM information_schema.columns
WHERE table_schema=:database AND table_name = :table
ORDER BY ordinal_position';
$result = dbtng_query($sql, array(':database' => $database, ':table' => $table));
foreach ($result as $row) {
$fields[$row->column_name] = $table . '.' . $row->column_name;
}
}
}*/
$database = 'plants';
$table = $table['table'];
$sql = 'SELECT column_name
FROM information_schema.columns
WHERE table_schema=:database AND table_name = :table
ORDER BY ordinal_position';
$result = dbtng_query($sql, array(':database' => $database, ':table' => $table));
foreach ($result as $row) {
$fields[$row->column_name] = $table . '.' . $row->column_name;
}
}
}*/
$expressionFields = $this->query->getExpressions();
foreach ($expressionFields as $field_name => $field_info) {
$fields[$field_name] = $field_info['alias'];
@@ -355,7 +358,7 @@ class MigrateSourceSQL extends MigrateSource {
}
$alias = $this->query->leftJoin($this->activeMap->getQualifiedMapTable(),
'map', $map_join);
'map', $map_join);
$conditions->isNull($alias . '.sourceid1');
$conditions->condition($alias . '.needs_update', MigrateMap::STATUS_NEEDS_UPDATE);
$condition_added = TRUE;

View File

@@ -6,15 +6,18 @@
*/
class MigrateSQLMap extends MigrateMap {
/**
* Names of tables created for tracking the migration.
*
* @var string
*/
protected $mapTable, $messageTable;
public function getMapTable() {
return $this->mapTable;
}
public function getMessageTable() {
return $this->messageTable;
}
@@ -36,7 +39,13 @@ class MigrateSQLMap extends MigrateMap {
return $this->mapTable;
}
else {
return $options['database'] . '.' . $this->mapTable;
$dbname = $options['database'];
if (!empty($options['driver']) && $options['driver'] == 'mysql') {
// Backtick the db name on mysql to ensure dbs with hyphens work.
$dbname = "`{$dbname}`";
}
return $dbname . '.' . $this->mapTable;
}
}
@@ -49,15 +58,18 @@ class MigrateSQLMap extends MigrateMap {
public function getSourceKey() {
return $this->sourceKey;
}
public function getDestinationKey() {
return $this->destinationKey;
}
/**
* Drupal connection object on which to create the map/message tables
*
* @var DatabaseConnection
*/
protected $connection;
public function getConnection() {
return $this->connection;
}
@@ -84,7 +96,7 @@ class MigrateSQLMap extends MigrateMap {
* @param array $destination_key
* The database schema for the destination key.
* @param string $connection_key
* Optional - The connection used to create the mapping tables. By default
* Optional - The connection used to create the mapping tables. By default
* this is the destination (Drupal). If it's not possible to make joins
* between the destination database and your source database you can specify
* a different connection to create the mapping tables on.
@@ -92,7 +104,7 @@ class MigrateSQLMap extends MigrateMap {
* Optional - Options applied to this source.
*/
public function __construct($machine_name, array $source_key,
array $destination_key, $connection_key = 'default', $options = array()) {
array $destination_key, $connection_key = 'default', $options = array()) {
if (isset($options['track_last_imported'])) {
$this->trackLastImported = TRUE;
}
@@ -107,7 +119,7 @@ class MigrateSQLMap extends MigrateMap {
$this->connection = Database::getConnection('default', $connection_key);
// Default generated table names, limited to 63 characters
$prefixLength = strlen($this->connection->tablePrefix()) ;
$prefixLength = strlen($this->connection->tablePrefix());
$this->mapTable = 'migrate_map_' . drupal_strtolower($machine_name);
$this->mapTable = drupal_substr($this->mapTable, 0, 63 - $prefixLength);
$this->messageTable = 'migrate_message_' . drupal_strtolower($machine_name);
@@ -143,6 +155,7 @@ class MigrateSQLMap extends MigrateMap {
foreach ($this->sourceKey as $field_schema) {
$mapkey = 'sourceid' . $count++;
$source_key_schema[$mapkey] = $field_schema;
$source_key_schema[$mapkey]['not null'] = TRUE;
$pks[] = $mapkey;
}
@@ -154,6 +167,7 @@ class MigrateSQLMap extends MigrateMap {
foreach ($this->destinationKey as $field_schema) {
// Allow dest key fields to be NULL (for IGNORED/FAILED cases)
$field_schema['not null'] = FALSE;
$field_schema['default'] = NULL;
$mapkey = 'destid' . $count++;
$fields[$mapkey] = $field_schema;
}
@@ -224,18 +238,19 @@ class MigrateSQLMap extends MigrateMap {
else {
// Add any missing columns to the map table
if (!$this->connection->schema()->fieldExists($this->mapTable,
'rollback_action')) {
'rollback_action')) {
$this->connection->schema()->addField($this->mapTable,
'rollback_action', array(
'type' => 'int',
'size' => 'tiny',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
'description' => 'Flag indicating what to do for this item on rollback',
));
'rollback_action', array(
'type' => 'int',
'size' => 'tiny',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
'description' => 'Flag indicating what to do for this item on rollback',
));
}
if (!$this->connection->schema()->fieldExists($this->mapTable, 'hash')) {
if (!$this->connection->schema()
->fieldExists($this->mapTable, 'hash')) {
$this->connection->schema()->addField($this->mapTable, 'hash', array(
'type' => 'varchar',
'length' => '32',
@@ -256,7 +271,7 @@ class MigrateSQLMap extends MigrateMap {
public function getRowBySource(array $source_id) {
migrate_instrument_start('mapRowBySource');
$query = $this->connection->select($this->mapTable, 'map')
->fields('map');
->fields('map');
foreach ($this->sourceKeyMap as $key_name) {
$query = $query->condition("map.$key_name", array_shift($source_id), '=');
}
@@ -273,7 +288,7 @@ class MigrateSQLMap extends MigrateMap {
public function getRowByDestination(array $destination_id) {
migrate_instrument_start('getRowByDestination');
$query = $this->connection->select($this->mapTable, 'map')
->fields('map');
->fields('map');
foreach ($this->destinationKeyMap as $key_name) {
$query = $query->condition("map.$key_name", array_shift($destination_id), '=');
}
@@ -287,16 +302,17 @@ class MigrateSQLMap extends MigrateMap {
*
* @param int $count
* Maximum rows to return; defaults to 10,000
*
* @return array
* Array of map row objects with needs_update==1.
*/
public function getRowsNeedingUpdate($count) {
$rows = array();
$result = $this->connection->select($this->mapTable, 'map')
->fields('map')
->condition('needs_update', MigrateMap::STATUS_NEEDS_UPDATE)
->range(0, $count)
->execute();
->fields('map')
->condition('needs_update', MigrateMap::STATUS_NEEDS_UPDATE)
->range(0, $count)
->execute();
foreach ($result as $row) {
$rows[] = $row;
}
@@ -304,11 +320,12 @@ class MigrateSQLMap extends MigrateMap {
}
/**
* Given a (possibly multi-field) destination key, return the (possibly multi-field)
* source key mapped to it.
* Given a (possibly multi-field) destination key, return the (possibly
* multi-field) source key mapped to it.
*
* @param array $destination_id
* Array of destination key values.
*
* @return array
* Array of source key values, or NULL on failure.
*/
@@ -325,7 +342,7 @@ class MigrateSQLMap extends MigrateMap {
}
$query = $this->connection->select($this->mapTable, 'map')
->fields('map', $this->sourceKeyMap);
->fields('map', $this->sourceKeyMap);
foreach ($this->destinationKeyMap as $key_name) {
$query = $query->condition("map.$key_name", array_shift($destination_id), '=');
}
@@ -342,11 +359,12 @@ class MigrateSQLMap extends MigrateMap {
}
/**
* Given a (possibly multi-field) source key, return the (possibly multi-field)
* destination key it is mapped to.
* Given a (possibly multi-field) source key, return the (possibly
* multi-field) destination key it is mapped to.
*
* @param array $source_id
* Array of source key values.
*
* @return array
* Array of destination key values, or NULL on failure.
*/
@@ -363,7 +381,7 @@ class MigrateSQLMap extends MigrateMap {
}
$query = $this->connection->select($this->mapTable, 'map')
->fields('map', $this->destinationKeyMap);
->fields('map', $this->destinationKeyMap);
foreach ($this->sourceKeyMap as $key_name) {
$query = $query->condition("map.$key_name", array_shift($source_id), '=');
}
@@ -378,6 +396,7 @@ class MigrateSQLMap extends MigrateMap {
migrate_instrument_stop('lookupDestinationID');
return $destination_id;
}
/**
* Called upon import of one record, we record a mapping from the source key
* to the destination key. Also may be called, setting the third parameter to
@@ -397,26 +416,26 @@ class MigrateSQLMap extends MigrateMap {
* If hashing is enabled, the hash of the raw source row.
*/
public function saveIDMapping(stdClass $source_row, array $dest_ids,
$needs_update = MigrateMap::STATUS_IMPORTED,
$rollback_action = MigrateMap::ROLLBACK_DELETE, $hash = NULL) {
$needs_update = MigrateMap::STATUS_IMPORTED,
$rollback_action = MigrateMap::ROLLBACK_DELETE, $hash = NULL) {
migrate_instrument_start('saveIDMapping');
// Construct the source key
$keys = array();
foreach ($this->sourceKeyMap as $field_name => $key_name) {
// A NULL key value will fail.
if (is_null($source_row->$field_name)) {
if (is_null($source_row->{$field_name})) {
Migration::displayMessage(t(
'Could not save to map table due to NULL value for key field !field',
array('!field' => $field_name)));
migrate_instrument_stop('saveIDMapping');
return;
}
$keys[$key_name] = $source_row->$field_name;
$keys[$key_name] = $source_row->{$field_name};
}
$fields = array(
'needs_update' => (int)$needs_update,
'rollback_action' => (int)$rollback_action,
'needs_update' => (int) $needs_update,
'rollback_action' => (int) $rollback_action,
'hash' => $hash,
);
$count = 1;
@@ -476,8 +495,8 @@ class MigrateSQLMap extends MigrateMap {
*/
public function prepareUpdate() {
$this->connection->update($this->mapTable)
->fields(array('needs_update' => MigrateMap::STATUS_NEEDS_UPDATE))
->execute();
->fields(array('needs_update' => MigrateMap::STATUS_NEEDS_UPDATE))
->execute();
}
/**
@@ -501,7 +520,10 @@ class MigrateSQLMap extends MigrateMap {
public function importedCount() {
$query = $this->connection->select($this->mapTable);
$query->addExpression('COUNT(*)', 'count');
$query->condition('needs_update', array(MigrateMap::STATUS_IMPORTED, MigrateMap::STATUS_NEEDS_UPDATE), 'IN');
$query->condition('needs_update', array(
MigrateMap::STATUS_IMPORTED,
MigrateMap::STATUS_NEEDS_UPDATE,
), 'IN');
$count = $query->execute()->fetchField();
return $count;
}
@@ -547,7 +569,8 @@ class MigrateSQLMap extends MigrateMap {
}
/**
* Delete the map entry and any message table entries for the specified source row.
* Delete the map entry and any message table entries for the specified
* source row.
*
* @param array $source_key
*/
@@ -572,7 +595,8 @@ class MigrateSQLMap extends MigrateMap {
}
/**
* Delete the map entry and any message table entries for the specified destination row.
* Delete the map entry and any message table entries for the specified
* destination row.
*
* @param array $destination_key
*/
@@ -601,7 +625,7 @@ class MigrateSQLMap extends MigrateMap {
*/
public function setUpdate(array $source_key) {
$query = $this->connection->update($this->mapTable)
->fields(array('needs_update' => MigrateMap::STATUS_NEEDS_UPDATE));
->fields(array('needs_update' => MigrateMap::STATUS_NEEDS_UPDATE));
$count = 1;
foreach ($source_key as $key_value) {
$query->condition('sourceid' . $count++, $key_value);
@@ -649,7 +673,7 @@ class MigrateSQLMap extends MigrateMap {
*/
public function clearMessages() {
$this->connection->truncate($this->messageTable)
->execute();
->execute();
}
/**
@@ -661,15 +685,18 @@ class MigrateSQLMap extends MigrateMap {
}
protected $result = NULL;
protected $currentRow = NULL;
protected $currentKey = array();
public function getCurrentKey() {
return $this->currentKey;
}
/**
* Implementation of Iterator::rewind() - called before beginning a foreach loop.
* TODO: Support idlist, itemlimit
* Implementation of Iterator::rewind() - called before beginning a foreach
* loop. TODO: Support idlist, itemlimit
*/
public function rewind() {
$this->currentRow = NULL;
@@ -701,17 +728,18 @@ class MigrateSQLMap extends MigrateMap {
}
/**
* Implementation of Iterator::key - called when entering a loop iteration, returning
* the key of the current row. It must be a scalar - we will serialize
* to fulfill the requirement, but using getCurrentKey() is preferable.
* Implementation of Iterator::key - called when entering a loop iteration,
* returning the key of the current row. It must be a scalar - we will
* serialize to fulfill the requirement, but using getCurrentKey() is
* preferable.
*/
public function key() {
return serialize($this->currentKey);
}
/**
* Implementation of Iterator::next() - called at the bottom of the loop implicitly,
* as well as explicitly from rewind().
* Implementation of Iterator::next() - called at the bottom of the loop
* implicitly, as well as explicitly from rewind().
*/
public function next() {
$this->currentRow = $this->result->fetchObject();
@@ -721,16 +749,16 @@ class MigrateSQLMap extends MigrateMap {
}
else {
foreach ($this->sourceKeyMap as $map_field) {
$this->currentKey[$map_field] = $this->currentRow->$map_field;
$this->currentKey[$map_field] = $this->currentRow->{$map_field};
// Leave only destination fields
unset($this->currentRow->$map_field);
unset($this->currentRow->{$map_field});
}
}
}
/**
* Implementation of Iterator::valid() - called at the top of the loop, returning
* TRUE to process the loop and FALSE to terminate it
* Implementation of Iterator::valid() - called at the top of the loop,
* returning TRUE to process the loop and FALSE to terminate it
*/
public function valid() {
// TODO: Check numProcessed against itemlimit

View File

@@ -20,11 +20,13 @@
/* ========================================================================== */
/* List Method */
/* ========================================================================== */
/**
* Implementation of MigrateList, for retrieving a list of IDs to be migrated
* from an XML document.
*/
class MigrateListXML extends MigrateList {
/**
* A URL pointing to an XML document containing a list of IDs to be processed.
*
@@ -157,6 +159,7 @@ class MigrateListXML extends MigrateList {
* an ID provided by a MigrateList class.
*/
class MigrateItemXML extends MigrateItem {
/**
* A URL pointing to an XML document containing the data for one item to be
* migrated.
@@ -282,6 +285,7 @@ class MigrateItemXML extends MigrateItem {
* Adds xpath info to field mappings for XML sources
*/
class MigrateXMLFieldMapping extends MigrateFieldMapping {
/**
* The xpath used to retrieve the data for this field from the XML.
*
@@ -315,6 +319,7 @@ class MigrateXMLFieldMapping extends MigrateFieldMapping {
* Migrations using XML sources should extend this class instead of Migration.
*/
abstract class XMLMigration extends Migration {
/**
* {@inheritdoc}
*
@@ -370,7 +375,7 @@ abstract class XMLMigration extends Migration {
// Derived class may override applyXpath().
$source_value = $this->applyXpath($this->sourceValues, $xpath);
if (!is_null($source_value)) {
$this->sourceValues->$source = $source_value;
$this->sourceValues->{$source} = $source_value;
}
}
}
@@ -414,11 +419,13 @@ abstract class XMLMigration extends Migration {
/* ========================================================================== */
/* MultiItems Method */
/* ========================================================================== */
/**
* Implementation of MigrateItems, for providing a list of IDs and for
* retrieving a parsed XML document given an ID from this list.
*/
class MigrateItemsXML extends MigrateItems {
/**
* An array with all urls to available xml files.
*
@@ -813,7 +820,7 @@ class MigrateItemsXML extends MigrateItems {
$this->getIdList();
}
foreach ($this->idsMap as $url => $ids) {
if (in_array($id, $ids)) {
if (in_array($id, $ids, TRUE)) {
$this->currentItems = NULL;
$this->currentUrl = $url;
$items = $this->getAllItems();
@@ -972,7 +979,7 @@ class MigrateXMLReader implements Iterator {
if ($attribute_query) {
// Matches [@attribute="value"] (with either single- or double-quotes).
preg_match_all('|^\[@([^=]+)=[\'"](.*)[\'"]\]$|', $attribute_query,
$matches);
$matches);
$this->attributeName = $matches[1][0];
$this->attributeValue = $matches[2][0];
}
@@ -1002,7 +1009,7 @@ class MigrateXMLReader implements Iterator {
}
else {
Migration::displayMessage(t('Could not open XML file !url',
array('!url' => $this->url)));
array('!url' => $this->url)));
}
}
@@ -1028,7 +1035,7 @@ class MigrateXMLReader implements Iterator {
// attribute, check that as well before accepting this element.
if (empty($this->attributeName) ||
($this->reader->getAttribute($this->attributeName) ==
$this->attributeValue)
$this->attributeValue)
) {
// We've found a matching element - get a SimpleXML object
// representing it.We must associate the DOMNode with a
@@ -1249,8 +1256,8 @@ class MigrateSourceXML extends MigrateSource {
// a lot of urls, may need to hash.
$urls = implode(', ', $this->sourceUrls);
return 'urls = ' . $urls .
' | item xpath = ' . $this->elementQuery .
' | item ID xpath = ' . $this->idQuery;
' | item xpath = ' . $this->elementQuery .
' | item ID xpath = ' . $this->idQuery;
}
/**
@@ -1283,7 +1290,7 @@ class MigrateSourceXML extends MigrateSource {
$count = 0;
foreach ($this->sourceUrls as $url) {
$reader = new $this->readerClass($url, $this->elementQuery,
$this->idQuery);
$this->idQuery);
foreach ($reader as $element) {
$count++;
}
@@ -1326,7 +1333,7 @@ class MigrateSourceXML extends MigrateSource {
// Test the reader for a valid row.
if (isset($this->reader) && $this->reader->valid()) {
$row = new stdClass();
$row->$key_name = $this->reader->key();
$row->{$key_name} = $this->reader->key();
$row->xml = $this->reader->current();
$this->registerNamespaces($row->xml);
}
@@ -1334,7 +1341,7 @@ class MigrateSourceXML extends MigrateSource {
// The current source is at the end, try to load the next source.
if ($this->getNextSource()) {
$row = new stdClass();
$row->$key_name = $this->reader->key();
$row->{$key_name} = $this->reader->key();
$row->xml = $this->reader->current();
$this->registerNamespaces($row->xml);
}

View File

@@ -9,6 +9,7 @@
* Test node migration.
*/
class MigrateImportOptionsTest extends DrupalWebTestCase {
public static function getInfo() {
return array(
'name' => 'Import options',

View File

@@ -9,6 +9,7 @@
* Test comment migration.
*/
class MigrateCommentUnitTest extends DrupalWebTestCase {
public static function getInfo() {
return array(
'name' => 'Comment migration',
@@ -62,18 +63,29 @@ class MigrateCommentUnitTest extends DrupalWebTestCase {
$this->assertEqual($result, Migration::RESULT_COMPLETED,
t('Comment import returned RESULT_COMPLETED'));
$result = db_select('migrate_message_winecomment', 'w')
->fields('w', array('message'))
->execute();
->fields('w', array('message'))
->execute();
foreach ($result as $row) {
$this->error($row->message);
}
$result = db_select('migrate_example_wine_comment', 'wc')
->fields('wc', array('commentid', 'comment_parent', 'name', 'mail',
'accountid', 'body', 'wineid', 'subject', 'commenthost', 'userpage',
'posted', 'lastchanged'))
->orderBy('comment_parent')
->execute();
->fields('wc', array(
'commentid',
'comment_parent',
'name',
'mail',
'accountid',
'body',
'wineid',
'subject',
'commenthost',
'userpage',
'posted',
'lastchanged',
))
->orderBy('comment_parent')
->execute();
$rawcomments = comment_load_multiple(FALSE);
// Index by subject
@@ -96,7 +108,8 @@ class MigrateCommentUnitTest extends DrupalWebTestCase {
$this->assertEqual($comment->name, $row->name, t('Name matches'));
$this->assertEqual($comment->status, COMMENT_PUBLISHED, t('Status matches'));
$wine_migration = MigrationBase::getInstance('WineWine');
$destid = $wine_migration->getMap()->lookupDestinationID(array($row->wineid));
$destid = $wine_migration->getMap()
->lookupDestinationID(array($row->wineid));
$this->assertEqual($comment->nid, reset($destid), t('Nid matches'));
$body = field_get_items('comment', $comment, 'comment_body');
$this->assertEqual($body[0]['value'], $row->body, t('Body matches'));
@@ -108,7 +121,8 @@ class MigrateCommentUnitTest extends DrupalWebTestCase {
$comment = $comments['im child'];
$row = $rows['im child'];
$user_migration = MigrationBase::getInstance('WineUser');
$destid = $user_migration->getMap()->lookupDestinationID(array($row->accountid));
$destid = $user_migration->getMap()
->lookupDestinationID(array($row->accountid));
$this->assertEqual($comment->uid, reset($destid), t('Uid matches'));
$this->assertEqual($comment->pid, $comments['im parent']->cid, t('Parent matches'));
@@ -123,16 +137,19 @@ class MigrateCommentUnitTest extends DrupalWebTestCase {
foreach ($original_comments as $cid => $original_comment) {
foreach ($original_comment as $field => $value) {
if ($field == 'subject') {
if ($value == $final_comments[$cid]->$field) {
if ($value == $final_comments[$cid]->{$field}) {
$this->error(t('Field !field should have changed but did not, value=!value',
array('!field' => $field, '!value' => print_r($value, TRUE))));
}
}
else {
if ($value != $final_comments[$cid]->$field) {
if ($value != $final_comments[$cid]->{$field}) {
$this->error(t('Field !field mismatch: original !value1, result !value2',
array('!field' => $field, '!value1' => print_r($value, TRUE),
'!value2' => print_r($final_comments[$cid]->$field, TRUE))));
array(
'!field' => $field,
'!value1' => print_r($value, TRUE),
'!value2' => print_r($final_comments[$cid]->{$field}, TRUE),
)));
}
}
}
@@ -145,16 +162,16 @@ class MigrateCommentUnitTest extends DrupalWebTestCase {
$rawcomments = comment_load_multiple(FALSE);
$this->assertEqual(count($rawcomments), 0, t('All comments deleted'));
$count = db_select('migrate_map_winecomment', 'map')
->fields('map', array('sourceid1'))
->countQuery()
->execute()
->fetchField();
->fields('map', array('sourceid1'))
->countQuery()
->execute()
->fetchField();
$this->assertEqual($count, 0, t('Map cleared'));
$count = db_select('migrate_message_winecomment', 'msg')
->fields('msg', array('sourceid1'))
->countQuery()
->execute()
->fetchField();
->fields('msg', array('sourceid1'))
->countQuery()
->execute()
->fetchField();
$this->assertEqual($count, 0, t('Messages cleared'));
}
}

View File

@@ -9,6 +9,7 @@
* Test node migration.
*/
class MigrateNodeUnitTest extends DrupalWebTestCase {
public static function getInfo() {
return array(
'name' => 'Node migration',
@@ -67,7 +68,13 @@ class MigrateNodeUnitTest extends DrupalWebTestCase {
}
$query = db_select('migrate_example_wine_producer', 'p')
->fields('p', array('producerid', 'name', 'body', 'excerpt', 'accountid'));
->fields('p', array(
'producerid',
'name',
'body',
'excerpt',
'accountid',
));
// Region term is singletons, handled straighforwardly
$query->leftJoin('migrate_example_wine_category_producer', 'reg',
"p.producerid = reg.producerid");
@@ -87,8 +94,17 @@ class MigrateNodeUnitTest extends DrupalWebTestCase {
$wine_nodes[$node->title] = $node;
}
$query = db_select('migrate_example_wine', 'w')
->fields('w', array('wineid', 'name', 'body', 'excerpt', 'accountid',
'posted', 'last_changed', 'variety', 'region'));
->fields('w', array(
'wineid',
'name',
'body',
'excerpt',
'accountid',
'posted',
'last_changed',
'variety',
'region',
));
$query->leftJoin('migrate_example_wine_category_wine', 'cwbw',
"w.wineid = cwbw.wineid");
$query->leftJoin('migrate_example_wine_categories', 'bw',
@@ -111,7 +127,8 @@ class MigrateNodeUnitTest extends DrupalWebTestCase {
$wine_row = $wine_rows['Montes Classic Cabernet Sauvignon'];
$user_migration = MigrationBase::getInstance('WineUser');
$mapped_uid = $user_migration->getMap()->lookupDestinationID(array($producer_row->accountid));
$mapped_uid = $user_migration->getMap()
->lookupDestinationID(array($producer_row->accountid));
if (is_array($mapped_uid)) {
$this->assertEqual($producer_node->uid, reset($mapped_uid),
t('uid properly migrated'));
@@ -134,7 +151,8 @@ class MigrateNodeUnitTest extends DrupalWebTestCase {
// taxonomy_term_reference - single and multiple
$variety = field_get_items('node', $wine_node, 'migrate_example_wine_varieties');
$variety_migration = MigrationBase::getInstance('WineVariety');
$mapped_tid = $variety_migration->getMap()->lookupDestinationID(array($wine_row->variety));
$mapped_tid = $variety_migration->getMap()
->lookupDestinationID(array($wine_row->variety));
if (is_array($mapped_tid)) {
$this->assertEqual($variety[0]['tid'], reset($mapped_tid),
t('Single taxonomy_term_reference properly migrated'));
@@ -147,7 +165,8 @@ class MigrateNodeUnitTest extends DrupalWebTestCase {
$source_ids = explode(',', $wine_row->best_with);
$mapped_tids = array();
foreach ($source_ids as $source_id) {
$tid = $best_with_migration->getMap()->lookupDestinationID(array($source_id));
$tid = $best_with_migration->getMap()
->lookupDestinationID(array($source_id));
if ($tid) {
$mapped_tids[reset($tid)] = reset($tid);
}
@@ -176,33 +195,66 @@ class MigrateNodeUnitTest extends DrupalWebTestCase {
foreach ($original_nodes as $nid => $original_node) {
foreach ($original_node as $field => $value) {
if ($field == 'field_migrate_example_wine_ratin' || $field == 'changed' || $field == 'revision_timestamp') {
if ($value == $final_nodes[$nid]->$field) {
if ($value == $final_nodes[$nid]->{$field}) {
$this->error(t('Field !field should have changed but did not, value=!value',
array('!field' => $field, '!value' => print_r($value, TRUE))));
}
}
else {
if ($value != $final_nodes[$nid]->$field) {
if ($value != $final_nodes[$nid]->{$field}) {
$this->error(t('Field !field mismatch: original !value1, result !value2',
array('!field' => $field, '!value1' => print_r($value, TRUE),
'!value2' => print_r($final_nodes[$nid]->$field, TRUE))));
array(
'!field' => $field,
'!value1' => print_r($value, TRUE),
'!value2' => print_r($final_nodes[$nid]->{$field}, TRUE),
)));
}
}
}
}
// Test highwater marks - add new wines, modify an old one, and see what changes
$fields = array('wineid', 'name', 'body', 'excerpt', 'accountid',
'posted', 'last_changed', 'variety', 'region', 'rating');
$fields = array(
'wineid',
'name',
'body',
'excerpt',
'accountid',
'posted',
'last_changed',
'variety',
'region',
'rating',
);
$query = db_insert('migrate_example_wine')
->fields($fields);
->fields($fields);
$data = array(
// Timestamps 1284008523, 1284120550
array(3, 'Schloss Muhlenhof Dornfelder', 'Juicy black & red berry fruits', 'Pretty good', 9,
strtotime('2010-09-09 01:02:03'), strtotime('2010-09-10 08:09:10'), 25, 17, 95),
array(
3,
'Schloss Muhlenhof Dornfelder',
'Juicy black & red berry fruits',
'Pretty good',
9,
strtotime('2010-09-09 01:02:03'),
strtotime('2010-09-10 08:09:10'),
25,
17,
95,
),
// Timestamps 1286122209, 1286122209
array(4, 'Gachot-Monot Bourgogne Rge 06', 'Funky', 'Pair with white sauced dishes', 3,
strtotime('2010-10-03 12:10:09'), strtotime('2010-10-03 12:10:09'), 26, 2, 85),
array(
4,
'Gachot-Monot Bourgogne Rge 06',
'Funky',
'Pair with white sauced dishes',
3,
strtotime('2010-10-03 12:10:09'),
strtotime('2010-10-03 12:10:09'),
26,
2,
85,
),
);
foreach ($data as $row) {
$query->values(array_combine($fields, $row));
@@ -211,9 +263,9 @@ class MigrateNodeUnitTest extends DrupalWebTestCase {
db_update('migrate_example_wine')
->fields(array(
'body' => 'Not so much berry character',
// Timestamp 1285058521
'last_changed' => strtotime('2010-10-21 04:42:01'),
'body' => 'Not so much berry character',
// Timestamp 1285058521
'last_changed' => strtotime('2010-10-21 04:42:01'),
))
->condition('wineid', 2)
->execute();
@@ -241,22 +293,24 @@ class MigrateNodeUnitTest extends DrupalWebTestCase {
$rawnodes = node_load_multiple(FALSE, array('type' => 'migrate_example_wine'), TRUE);
$this->assertEqual(count($rawnodes), 0, t('All nodes deleted'));
$count = db_select('migrate_map_winewine', 'map')
->fields('map', array('sourceid1'))
->countQuery()
->execute()
->fetchField();
->fields('map', array('sourceid1'))
->countQuery()
->execute()
->fetchField();
$this->assertEqual($count, 0, t('Map cleared'));
$count = db_select('migrate_message_winewine', 'msg')
->fields('msg', array('sourceid1'))
->countQuery()
->execute()
->fetchField();
->fields('msg', array('sourceid1'))
->countQuery()
->execute()
->fetchField();
$this->assertEqual($count, 0, t('Messages cleared'));
// Now test highwater with unjoined map table
$migration->getSource()->setMapJoinable(FALSE);
$result = $migration->processImport(array('limit' =>
array('value' => 2, 'unit' => 'items')));
$result = $migration->processImport(array(
'limit' =>
array('value' => 2, 'unit' => 'items'),
));
db_update('migrate_example_wine')
->fields(array(
'body' => 'Very berry',
@@ -282,8 +336,10 @@ class MigrateNodeUnitTest extends DrupalWebTestCase {
// Test itemlimit (joined map table)
$result = $migration->processRollback(array('force' => TRUE));
$migration->getSource()->setMapJoinable(TRUE);
$result = $migration->processImport(array('limit' =>
array('value' => 1, 'unit' => 'item')));
$result = $migration->processImport(array(
'limit' =>
array('value' => 1, 'unit' => 'item'),
));
$this->assertEqual($result, Migration::RESULT_COMPLETED,
t('Wine node import with itemlimit returned RESULT_COMPLETED'));
$rawnodes = node_load_multiple(FALSE, array('type' => 'migrate_example_wine'), TRUE);
@@ -303,8 +359,10 @@ class MigrateNodeUnitTest extends DrupalWebTestCase {
// Test itemlimit (unjoined map table)
$result = $migration->processRollback(array('force' => TRUE));
$migration->getSource()->setMapJoinable(FALSE);
$result = $migration->processImport(array('limit' =>
array('value' => 1, 'unit' => 'item')));
$result = $migration->processImport(array(
'limit' =>
array('value' => 1, 'unit' => 'item'),
));
$this->assertEqual($result, Migration::RESULT_COMPLETED,
t('Wine node import with itemlimit returned RESULT_COMPLETED'));
$rawnodes = node_load_multiple(FALSE, array('type' => 'migrate_example_wine'), TRUE);
@@ -359,10 +417,10 @@ class MigrateNodeUnitTest extends DrupalWebTestCase {
->execute();
$result = $migration->processImport();
$newHighwater = db_select('migrate_status', 'ms')
->fields('ms', array('highwater'))
->condition('machine_name', 'WineWine')
->execute()
->fetchField();
->fields('ms', array('highwater'))
->condition('machine_name', 'WineWine')
->execute()
->fetchField();
if (!$this->assertEqual($newHighwater, 1000000000, t('Correct highwater mark set'))) {
$this->error(t('Unexpected highwater mark !highwater', array('!highwater' => $newHighwater)));
}
@@ -387,10 +445,23 @@ class MigrateNodeUnitTest extends DrupalWebTestCase {
$this->assertEqual($result, Migration::RESULT_COMPLETED,
t('Beer node update import returned RESULT_COMPLETED'));
$result = db_select('migrate_message_beernode', 'msg')
->fields('msg', array('message'))
->execute();
->fields('msg', array('message'))
->execute();
foreach ($result as $row) {
$this->error($row->message);
}
// Test proper disableMailSystem()/restoreMailSystem() behavior.
// @see https://www.drupal.org/node/2499861
// This is not necessarily node-related, but it was shoved in the node test.
$migration->saveMailSystem();
$migration->disableMailSystem();
$ms = variable_get('mail_system', NULL);
$this->assertTrue(is_array($ms) && in_array('MigrateMailIgnore', $ms),
t('Migration has disabled mail system'));
$migration->restoreMailSystem();
$ms = variable_get('mail_system', NULL);
$this->assertFalse(is_array($ms) && in_array('MigrateMailIgnore', $ms),
t('Migration::restoreMailSystem restored mail system'));
}
}

View File

@@ -9,6 +9,7 @@
* Test table migration.
*/
class MigrateTableUnitTest extends DrupalWebTestCase {
public static function getInfo() {
return array(
'name' => 'Table migration',

View File

@@ -9,6 +9,7 @@
* Test taxonomy migration.
*/
class MigrateTaxonomyUnitTest extends DrupalWebTestCase {
public static function getInfo() {
return array(
'name' => 'Taxonomy migration',
@@ -36,10 +37,16 @@ class MigrateTaxonomyUnitTest extends DrupalWebTestCase {
$terms[$term->name] = $term;
}
$query = db_select('migrate_example_wine_categories', 'wc')
->fields('wc', array('categoryid', 'name', 'details', 'category_parent', 'ordering'))
->condition('wc.type', 'variety');
->fields('wc', array(
'categoryid',
'name',
'details',
'category_parent',
'ordering',
))
->condition('wc.type', 'variety');
$query->leftJoin('migrate_example_wine_categories', 'wcpar',
'wc.category_parent=wcpar.categoryid');
'wc.category_parent=wcpar.categoryid');
$query->addField('wcpar', 'name', 'parent_name');
$result = $query->execute();
@@ -79,16 +86,19 @@ class MigrateTaxonomyUnitTest extends DrupalWebTestCase {
foreach ($original_terms as $tid => $original_term) {
foreach ($original_term as $field => $value) {
if ($field == 'description') {
if ($value == $final_terms[$tid]->$field) {
if ($value == $final_terms[$tid]->{$field}) {
$this->error(t('Field !field should have changed but did not, value=!value',
array('!field' => $field, '!value' => print_r($value, TRUE))));
}
}
else {
if ($value != $final_terms[$tid]->$field) {
if ($value != $final_terms[$tid]->{$field}) {
$this->error(t('Field !field mismatch: original !value1, result !value2',
array('!field' => $field, '!value1' => print_r($value, TRUE),
'!value2' => print_r($final_terms[$tid]->$field, TRUE))));
array(
'!field' => $field,
'!value1' => print_r($value, TRUE),
'!value2' => print_r($final_terms[$tid]->{$field}, TRUE),
)));
}
}
}
@@ -101,16 +111,16 @@ class MigrateTaxonomyUnitTest extends DrupalWebTestCase {
$rawterms = taxonomy_term_load_multiple(array(), array('vid' => $vocab->vid));
$this->assertEqual(count($rawterms), 0, t('All terms deleted'));
$count = db_select('migrate_map_winevariety', 'map')
->fields('map', array('sourceid1'))
->countQuery()
->execute()
->fetchField();
->fields('map', array('sourceid1'))
->countQuery()
->execute()
->fetchField();
$this->assertEqual($count, 0, t('Map cleared'));
$count = db_select('migrate_message_winevariety', 'msg')
->fields('msg', array('sourceid1'))
->countQuery()
->execute()
->fetchField();
->fields('msg', array('sourceid1'))
->countQuery()
->execute()
->fetchField();
$this->assertEqual($count, 0, t('Messages cleared'));
}
}

View File

@@ -9,6 +9,7 @@
* Test user migration.
*/
class MigrateUserUnitTest extends DrupalWebTestCase {
public static function getInfo() {
return array(
'name' => 'User migration',
@@ -38,9 +39,9 @@ class MigrateUserUnitTest extends DrupalWebTestCase {
t('Role import returned RESULT_COMPLETED'));
// Confirm both roles were successfully imported
$result = db_select('role', 'r')
->fields('r', array('rid', 'name'))
->condition('name', array('Taster', 'Vintner'), 'IN')
->execute();
->fields('r', array('rid', 'name'))
->condition('name', array('Taster', 'Vintner'), 'IN')
->execute();
$roles = array();
foreach ($result as $row) {
$roles[$row->name] = $row->rid;
@@ -59,14 +60,24 @@ class MigrateUserUnitTest extends DrupalWebTestCase {
$this->assertEqual($result, Migration::RESULT_COMPLETED,
t('User import returned RESULT_COMPLETED'));
$result = db_select('migrate_example_wine_account', 'mea')
->fields('mea', array('accountid', 'status', 'posted', 'name',
'sex', 'password', 'mail', 'last_access', 'last_login',
'sig', 'original_mail'))
->execute();
->fields('mea', array(
'accountid',
'status',
'posted',
'name',
'sex',
'password',
'mail',
'last_access',
'last_login',
'sig',
'original_mail',
))
->execute();
$uids = db_select('users', 'u')
->fields('u', array('uid'))
->execute()
->fetchCol();
->fields('u', array('uid'))
->execute()
->fetchCol();
// Index by name
$users = array();
foreach ($uids as $uid) {
@@ -114,10 +125,10 @@ class MigrateUserUnitTest extends DrupalWebTestCase {
1, t('Female gender migrated'));
$this->assert(!isset($users['fonzie']->field_migrate_example_gender[LANGUAGE_NONE][0]['value']),
t('Missing gender left unmigrated'));
/* For some reason, this fails on d.o but not in local environments
$this->assert(is_object($users['fonzie']->picture) &&
$users['fonzie']->picture->filename == '200',
t('Picture migrated'));*/
/* For some reason, this fails on d.o but not in local environments
$this->assert(is_object($users['fonzie']->picture) &&
$users['fonzie']->picture->filename == '200',
t('Picture migrated'));*/
$this->assertNotNull($users['fonzie']->roles[$roles['Taster']], t('Taster role'));
$this->assertNotNull($users['fonzie']->roles[$roles['Vintner']], t('Vintner role'));
@@ -140,20 +151,26 @@ class MigrateUserUnitTest extends DrupalWebTestCase {
foreach ($original_users as $uid => $original_user) {
foreach ($original_user as $field => $value) {
if ($field == 'field_migrate_example_gender') {
if ($value == $final_users[$uid]->$field) {
if ($value == $final_users[$uid]->{$field}) {
$this->error(t('For user !name, field !field should have changed but did not, value=!value',
array('!name' => $final_users[$uid]->name, '!field' => $field,
'!value' => print_r($value, TRUE))));
array(
'!name' => $final_users[$uid]->name,
'!field' => $field,
'!value' => print_r($value, TRUE),
)));
}
}
else {
if ($value != $final_users[$uid]->$field) {
if ($value != $final_users[$uid]->{$field}) {
// Core bug http://drupal.org/node/935592 causes picture mismatches, ignore until it's fixed
if ($field != 'picture') {
$this->error(t('For user !name, field !field mismatch: original !value1, result !value2',
array('!name' => $final_users[$uid]->name, '!field' => $field,
array(
'!name' => $final_users[$uid]->name,
'!field' => $field,
'!value1' => print_r($value, TRUE),
'!value2' => print_r($final_users[$uid]->$field, TRUE))));
'!value2' => print_r($final_users[$uid]->{$field}, TRUE),
)));
}
}
}
@@ -165,23 +182,23 @@ class MigrateUserUnitTest extends DrupalWebTestCase {
$this->assertEqual($result, Migration::RESULT_COMPLETED,
t('User rollback returned RESULT_COMPLETED'));
$count = db_select('users', 'u')
->fields('u', array('uid'))
->countQuery()
->execute()
->fetchField();
->fields('u', array('uid'))
->countQuery()
->execute()
->fetchField();
// 2 users left - anon and admin
$this->assertEqual($count, 2, t('All imported users deleted'));
$count = db_select('migrate_map_wineuser', 'map')
->fields('map', array('sourceid1'))
->countQuery()
->execute()
->fetchField();
->fields('map', array('sourceid1'))
->countQuery()
->execute()
->fetchField();
$this->assertEqual($count, 0, t('Map cleared'));
$count = db_select('migrate_message_wineuser', 'msg')
->fields('msg', array('sourceid1'))
->countQuery()
->execute()
->fetchField();
->fields('msg', array('sourceid1'))
->countQuery()
->execute()
->fetchField();
$this->assertEqual($count, 0, t('Messages cleared'));
// Test deduping
@@ -191,9 +208,9 @@ class MigrateUserUnitTest extends DrupalWebTestCase {
$this->assertEqual($result, Migration::RESULT_COMPLETED,
t('User import returned RESULT_COMPLETED'));
$accounts = db_select('users', 'u')
->fields('u', array('mail', 'name'))
->execute()
->fetchAllKeyed();
->fields('u', array('mail', 'name'))
->execute()
->fetchAllKeyed();
if (!$this->assertEqual($accounts['alice@example.com'], 'alice', t('alice found'))) {
$this->error(t('Expected alice, found !name', array('!name' => $accounts['alice@example.com'])));
}
@@ -207,9 +224,9 @@ class MigrateUserUnitTest extends DrupalWebTestCase {
$this->assertEqual($result, Migration::RESULT_COMPLETED,
t('User import returned RESULT_COMPLETED'));
$accounts = db_select('users', 'u')
->fields('u', array('mail', 'name'))
->execute()
->fetchAllKeyed();
->fields('u', array('mail', 'name'))
->execute()
->fetchAllKeyed();
if (!$this->assertEqual($accounts['alice@example.com'], 'alice', t('alice found'))) {
$this->error(t('Expected alice, found !name', array('!name' => $accounts['alice@example.com'])));
}

View File

@@ -12,6 +12,7 @@
* when that is fixed.
*/
class MigrateOracleUnitTest extends DrupalWebTestCase {
public static function getInfo() {
return array(
'name' => 'Oracle migration',
@@ -23,7 +24,7 @@ class MigrateOracleUnitTest extends DrupalWebTestCase {
function setUp() {
global $conf;
if (empty($conf['oracle_db']) || empty($conf['oracle_db']['username']) ||
empty($conf['oracle_db']['password']) || empty($conf['oracle_db']['connection_string'])) {
empty($conf['oracle_db']['password']) || empty($conf['oracle_db']['connection_string'])) {
parent::setUp();
}
else {
@@ -87,16 +88,16 @@ class MigrateOracleUnitTest extends DrupalWebTestCase {
$rawnodes = node_load_multiple(FALSE, array('type' => 'migrate_example_oracle'), TRUE);
$this->assertEqual(count($rawnodes), 0, t('All nodes deleted'));
$count = db_select('migrate_map_migrateexampleoracle', 'map')
->fields('map', array('sourceid1'))
->countQuery()
->execute()
->fetchField();
->fields('map', array('sourceid1'))
->countQuery()
->execute()
->fetchField();
$this->assertEqual($count, 0, t('Map cleared'));
$count = db_select('migrate_message_migrateexampleoracle', 'msg')
->fields('msg', array('sourceid1'))
->countQuery()
->execute()
->fetchField();
->fields('msg', array('sourceid1'))
->countQuery()
->execute()
->fetchField();
$this->assertEqual($count, 0, t('Messages cleared'));
}
}

View File

@@ -9,6 +9,7 @@
* Test node migration.
*/
class MigrateXMLUnitTest extends DrupalWebTestCase {
public static function getInfo() {
return array(
'name' => 'XML migration',
@@ -139,16 +140,16 @@ class MigrateXMLUnitTest extends DrupalWebTestCase {
$rawnodes = node_load_multiple(FALSE, array('type' => 'migrate_example_producer'), TRUE);
$this->assertEqual(count($rawnodes), 0, t('All nodes deleted'));
$count = db_select('migrate_map_wineproducerxml', 'map')
->fields('map', array('sourceid1'))
->countQuery()
->execute()
->fetchField();
->fields('map', array('sourceid1'))
->countQuery()
->execute()
->fetchField();
$this->assertEqual($count, 0, t('Map cleared'));
$count = db_select('migrate_message_wineproducerxml', 'msg')
->fields('msg', array('sourceid1'))
->countQuery()
->execute()
->fetchField();
->fields('msg', array('sourceid1'))
->countQuery()
->execute()
->fetchField();
$this->assertEqual($count, 0, t('Messages cleared'));
}
}

View File

@@ -3,9 +3,9 @@
/**
* @file
* Sample file for handling redirection from old to new URIs. Use an Apache
* rewrite rule (or equivalent) to map legacy requests to this file. To use, copy
* or symlink this file to the root of your drupal site. Customize
* this file to your needs.
* rewrite rule (or equivalent) to map legacy requests to this file. To use,
* copy or symlink this file to the root of your drupal site. Customize this
* file to your needs.
*
* CREATE TABLE `migrate_source_uri_map` (
* `source_uri` varchar(255) NOT NULL DEFAULT '',
@@ -41,7 +41,7 @@ function migrate_build_url($destid1, $migration_name) {
}
// Build absolute url for 301 redirect.
return $base_url . '/' . $destination_uri;
return $base_url . '/' . $destination_uri;
}
define('DRUPAL_ROOT', getcwd());