diff -u b/redirect.migrate.inc b/redirect.migrate.inc --- b/redirect.migrate.inc +++ b/redirect.migrate.inc @@ -11,8 +11,8 @@ /** * Constructor. */ - public function __construct() { - parent::__construct('redirect', 'redirect'); + public function __construct($bundle = 'redirect', array $options = array()) { + parent::__construct('redirect', $bundle, $options); } /** @@ -20,7 +20,7 @@ */ static public function getKeySchema() { return array( - 'rid' => array( + 'rid' => array( 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, @@ -45,18 +45,19 @@ */ public function fields() { return array( - 'rid' => 'Primary Key: Unique redirect ID.', - 'hash' => 'A unique hash based on source, source_options, and language.', - 'type' => "The redirect type; if value is 'redirect' it is a normal redirect handled by the module.", - 'uid' => 'The {users}.uid of the user who created the redirect.', - 'source' => 'The source path to redirect from.', - 'source_options' => 'A serialized array of source options.', - 'redirect' => 'The destination path to redirect to.', - 'redirect_options' => 'A serialized array of redirect options.', - 'language' => 'The language this redirect is for; if blank, the alias will be used for unknown languages.', - 'status_code' => 'The HTTP status code to use for the redirect.', - 'count' => 'The number of times the redirect has been used.', - 'access' => 'The timestamp of when the redirect was last accessed.' + 'rid' => t('Primary Key: Unique redirect ID.'), + 'hash' => t('A unique hash based on source, source_options, and language.'), + 'type' => t("The redirect type; if value is 'redirect' it is a normal redirect handled by the module."), + 'uid' => t('The {users}.uid of the user who created the redirect.'), + 'source' => t('The source path to redirect from.'), + 'source_options' => t('A serialized array of source options.'), + 'redirect' => t('The destination path to redirect to.'), + 'redirect_options' => t('A serialized array of redirect options.'), + 'language' => t('The language this redirect is for; if blank, the alias will be used for unknown languages.'), + 'status_code' => t('The HTTP status code to use for the redirect.'), + 'count' => t('The number of times the redirect has been used.'), + 'access' => t('The timestamp of when the redirect was last accessed.'), + 'is_new' => t('Option: Indicates a new redirect with the specified rid should be created'), ); } @@ -76,8 +77,9 @@ $migration = Migration::currentMigration(); if (url($redirect->source) == url($redirect->redirect)) { $migration->saveMessage(t('Redirect to self (!redirect) ignored', - array('!redirect' => $redirect->redirect)), - MigrationBase::MESSAGE_INFORMATIONAL); + array('!redirect' => $redirect->redirect)), + MigrationBase::MESSAGE_INFORMATIONAL); + return FALSE; } @@ -86,6 +88,7 @@ if ($redirect->rid != $existing->rid) { $migration->saveMessage(t('The source path is already being redirected.'), MigrationBase::MESSAGE_INFORMATIONAL); + return FALSE; } } @@ -103,48 +106,103 @@ * @return array * Array of key fields of the object that was saved if successful. FALSE on * failure. + * + * @throws MigrateException */ public function import(stdClass $redirect, stdClass $row) { - // Updating previously-migrated content + // Updating previously-migrated content? + $migration = Migration::currentMigration(); if (isset($row->migrate_map_destid1)) { - $redirect->rid = $row->migrate_map_destid1; + if (isset($redirect->rid)) { + // Make sure is_new is off. + $redirect->is_new = FALSE; + if ($redirect->rid != $row->migrate_map_destid1) { + throw new MigrateException(t("Incoming rid !rid and map destination rid !destid1 don't match", + array( + '!rid' => $redirect->rid, + '!destid1' => $row->migrate_map_destid1 + ))); + } + else { + $redirect->rid = $row->migrate_map_destid1; + } + } + } + if ($migration->getSystemOfRecord() == Migration::DESTINATION) { + if (!isset($redirect->rid)) { + throw new MigrateException(t('System-of-record is DESTINATION, but no destination rid provided')); + } + $old_redirect = redirect_load($redirect->rid); + if (empty($old_redirect)) { + throw new MigrateException(t('System-of-record is DESTINATION, but redirect !rid does not exist', + array('!rid' => $redirect->rid))); + } + } + elseif (!isset($redirect->type)) { + // Default the type to our designated destination bundle (by doing this + // conditionally, we permit some flexibility in terms of implementing + // migrations which can affect more than one type). + $redirect->type = $this->bundle; + } + + // Set some required properties. + if ($migration->getSystemOfRecord() == Migration::SOURCE) { + if (empty($redirect->language)) { + $redirect->language = $this->language; + } + } + + redirect_object_prepare($redirect); + + // Parse source and destination and extract options. + $this->extractUrlOptions($redirect, 'source'); + $this->extractUrlOptions($redirect, 'redirect'); + + // Handle provided hashes. + if (empty($redirect->hash)) { + $redirect->hash = redirect_hash($redirect); } - // Invoke migration prepare handlers + // Invoke migration prepare handlers. $this->prepare($redirect, $row); - migrate_instrument_start('redirect_save'); + // Trying to update an existing redirect. + if ($migration->getSystemOfRecord() == Migration::DESTINATION) { + // Incoming data overrides existing, so only copy non-existent fields. + foreach (array_keys($old_redirect) as $field) { + // An explicit NULL in the source data means to wipe to old value + // (i.e., don't copy it over from $old_redirect) + if (property_exists($redirect, $field) && $redirect->$field === NULL) { + // Ignore this field. + } + elseif (!isset($redirect->$field)) { + $redirect->$field = $old_redirect->$field; + } + } + } - // Check to see if this is a new redirect. - $update = FALSE; - if (isset($redirect->rid)) { - $update = TRUE; + if (isset($redirect->rid) && !(isset($redirect->is_new) && $redirect->is_new)) { + $updating = TRUE; } - // Prepare the redirect. - redirect_object_prepare($redirect); - $parsed = redirect_parse_url($redirect->source); - $redirect->source = isset($parsed['path']) ? $parsed['path'] : ''; - if (!empty($parsed['query'])) { - $redirect->source_options['query'] = $parsed['query']; + else { + $updating = FALSE; } + + // Only save if the redirect does not already exist. if ($this->redirectValidate($redirect)) { + migrate_instrument_start('redirect_save'); redirect_save($redirect); + migrate_instrument_stop('redirect_save'); } - else { - throw new MigrateException('The redirect was not valid.'); - } - migrate_instrument_stop('redirect_save'); - // Return the new id or FALSE on failure. - if (!empty($redirect->rid)) { - // Increment the count if the save succeeded. - if ($update) { + if (isset($redirect->rid)) { + if ($updating) { $this->numUpdated++; } else { $this->numCreated++; } - // Return the primary key to the mapping table. + $return = array($redirect->rid); } else { @@ -160,7 +218,7 @@ /** * Delete redirects. * - * @param array $id + * @param array $rids * IDs to be deleted. */ public function bulkRollback(array $rids) { @@ -172,66 +230,43 @@ } /** - * Implementation of MigrateDestination::prepare(). + * Extract the query and fragment parts out of an URL field. + * + * Inspired by _redirect_extract_url_options(). */ - public function prepare($redirect, stdClass $row) { - // We do nothing here but allow child classes to act. - $migration = Migration::currentMigration(); - $redirect->migrate = array( - 'machineName' => $migration->getMachineName(), - ); + protected function extractUrlOptions(stdClass &$redirect, $type) { + $url = &$redirect->{$type}; + $options_type = $type . '_options'; + $options = &$redirect->{$options_type}; - // Call any general handlers. - migrate_handler_invoke_all('redirect', 'prepare', $redirect, $row); - // Then call any prepare handler for this specific Migration. - if (method_exists($migration, 'prepare')) { - $migration->prepare($redirect, $row); + $parsed = redirect_parse_url($url); + + if (isset($parsed['fragment'])) { + $options['fragment'] = $parsed['fragment']; + } + else { + unset($options['fragment']); } - } - /** - * Implementation of MigrateDestination::complete(). - */ - public function complete($redirect, stdClass $row) { - // We do nothing here but allow child classes to act. - $migration = Migration::currentMigration(); - $redirect->migrate = array( - 'machineName' => $migration->getMachineName(), - ); - // Call any general handlers. - migrate_handler_invoke_all('redirect', 'complete', $redirect, $row); - // Then call any complete handler for this specific Migration. - if (method_exists($migration, 'complete')) { - $migration->complete($redirect, $row); + if (isset($parsed['query'])) { + $options['query'] = $parsed['query']; + } + else { + unset($options['query']); } - } - /** - * Implementation of MigrateDestination::prepareRollback(). - */ - public function prepareRollback($rid) { - // We do nothing here but allow child classes to act. - $migration = Migration::currentMigration(); - // Call any general handlers. - migrate_handler_invoke_all('redirect', 'prepareRollback', $rid); - // Then call any complete handler for this specific Migration. - if (method_exists($migration, 'prepareRollback')) { - $migration->prepareRollback($rid); + if (isset($parsed['scheme']) && $parsed['scheme'] == 'https') { + $options['https'] = TRUE; + } + else { + unset($options['https']); } - } - /** - * Implementation of MigrateDestination::completeRollback(). - */ - public function completeRollback($rid) { - // We do nothing here but allow child classes to act. - $migration = Migration::currentMigration(); - // Call any general handlers. - migrate_handler_invoke_all('redirect', 'completeRollback', $rid); - // Then call any complete handler for this specific Migration. - if (method_exists($migration, 'completeRollback')) { - $migration->completeRollback($rid); + if (!url_is_external($parsed['url'])) { + $parsed['url'] = drupal_get_normal_path($parsed['url'], $redirect->language); } + + $url = $parsed['url']; } }