Skip to content
<?php
/**
* @file
* Contains \Drupal\migrate\Plugin\migrate\destination\DestinationBase.
*/
namespace Drupal\migrate\Plugin\migrate\destination;
use Drupal\Core\Plugin\PluginBase;
use Drupal\migrate\Plugin\MigrateDestinationInterface;
abstract class DestinationBase extends PluginBase implements MigrateDestinationInterface {
/**
* Modify the Row before it is imported.
*/
public function preImport() {
// TODO: Implement preImport() method.
}
/**
* Modify the Row before it is rolled back.
*/
public function preRollback() {
// TODO: Implement preRollback() method.
}
public function postImport() {
// TODO: Implement postImport() method.
}
public function postRollback() {
// TODO: Implement postRollback() method.
}
public function rollbackMultiple(array $destination_identifiers) {
// TODO: Implement rollbackMultiple() method.
}
public function getCreated() {
// TODO: Implement getCreated() method.
}
public function getUpdated() {
// TODO: Implement getUpdated() method.
}
public function resetStats() {
// TODO: Implement resetStats() method.
}
}
<?php
/**
* @file
* Contains \Drupal\migrate\Plugin\migrate\process\DefaultValue.
*/
namespace Drupal\migrate\Plugin\migrate\process;
use Drupal\Core\Plugin\PluginBase;
use Drupal\migrate\MigrateExecutable;
use Drupal\migrate\Plugin\MigrateProcessInterface;
use Drupal\migrate\Row;
/**
* This plugin sets missing values on the destination.
*
* @PluginId("default_value")
*/
class DefaultValue extends PluginBase implements MigrateProcessInterface {
/**
* {@inheritdoc}
*/
public function transform($value, MigrateExecutable $migrate_executable, Row $row, $destination_property) {
return isset($value) ? $value : $this->configuration['default_value'];
}
}
<?php
/**
* @file
* Contains \Drupal\migrate\Plugin\migrate\process\CopyFromSource.
*/
namespace Drupal\migrate\Plugin\migrate\process;
use Drupal\Core\Plugin\PluginBase;
use Drupal\migrate\MigrateExecutable;
use Drupal\migrate\Plugin\MigrateProcessInterface;
use Drupal\migrate\Row;
/**
* This plugin copies from the source to the destination.
*
* @PluginId("get")
*/
class Get extends PluginBase implements MigrateProcessInterface {
/**
* {@inheritdoc}
*/
public function transform($value, MigrateExecutable $migrate_executable, Row $row, $destination_property) {
$source = $this->configuration['source'];
$properties = is_string($source) ? array($source) : $source;
$return = array();
foreach ($properties as $property) {
if (empty($property)) {
$return[] = $value;
}
else {
$is_source = TRUE;
if ($property[0] == '@') {
$property = preg_replace_callback('/^(@?)((?:@@)*)([^@]|$)/', function ($matches) use (&$is_source) {
// If there are an odd number of @ in the beginning, it's a
// destination.
$is_source = empty($matches[1]);
// Remove the possible escaping and do not lose the terminating
// non-@ either.
return str_replace('@@', '@', $matches[2]) . $matches[3];
}, $property);
}
if ($is_source) {
$return[] = $row->getSourceProperty($property);
}
else {
$return[] = $row->getDestinationProperty($property);
}
}
}
return is_string($source) ? $return[0] : $return;
}
}
<?php
/**
* @file
* Contains \Drupal\migrate\Plugin\migrate\source\d6\Variable.
*/
namespace Drupal\migrate\Plugin\migrate\source;
use Drupal\migrate\Entity\MigrationInterface;
use Drupal\migrate\Plugin\migrate\source\d6\Drupal6SqlBase;
/**
* Drupal 6 variable source from database.
*
* @PluginID("drupal6_variable")
*/
class D6Variable extends Drupal6SqlBase {
/**
* The variable names to fetch.
*
* @var array
*/
protected $variables;
/**
* {@inheritdoc}
*/
function __construct(array $configuration, $plugin_id, array $plugin_definition, MigrationInterface $migration) {
parent::__construct($configuration, $plugin_id, $plugin_definition, $migration);
$this->variables = $this->configuration['variables'];
}
protected function runQuery() {
return new \ArrayIterator(array(array_map('unserialize', $this->query()->execute()->fetchAllKeyed())));
}
public function count() {
return intval($this->query()->countQuery()->execute()->fetchField() > 0);
}
/**
* {@inheritdoc}
*/
public function fields() {
return drupal_map_assoc($this->variables);
}
/**
* {@inheritdoc}
*/
function query() {
return $this->getDatabase()
->select('variable', 'v')
->fields('v', array('name', 'value'))
->condition('name', $this->variables, 'IN');
}
}
<?php
/**
* @file
* Contains \Drupal\migrate\Plugin\migrate\source\SourcePluginBase.
*/
namespace Drupal\migrate\Plugin\migrate\source;
use Drupal\Core\Plugin\PluginBase;
use Drupal\migrate\Entity\MigrationInterface;
use Drupal\migrate\Plugin\MigrateSourceInterface;
use Drupal\migrate\Row;
abstract class SourcePluginBase extends PluginBase implements MigrateSourceInterface {
/**
* @var \Drupal\Core\Extension\ModuleHandlerInterface
*/
protected $moduleHandler;
/**
* @var \Drupal\migrate\Entity\MigrationInterface
*/
protected $migration;
/**
* {@inheritdoc}
*/
function __construct(array $configuration, $plugin_id, array $plugin_definition, MigrationInterface $migration) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->migration = $migration;
}
/**
* @return \Drupal\Core\Extension\ModuleHandlerInterface
*/
protected function getModuleHandler() {
if (!isset($this->moduleHandler)) {
$this->moduleHandler = \Drupal::moduleHandler();
}
return $this->moduleHandler;
}
/**
* {@inheritdoc}
*/
public function prepareRow(Row $row) {
$this->getModuleHandler()->invokeAll('migrate_prepare_row', $row, $this, $this->migration);
$this->getModuleHandler()->invokeAll('migrate_ '. $this->migration->id() . '_prepare_row', $row, $this, $this->migration);
return TRUE;
}
}
<?php
/**
* @file
* Contains \Drupal\migrate\Plugin\migrate\source\SqlBase.
*/
namespace Drupal\migrate\Plugin\migrate\source;
use Drupal\Core\Database\Database;
use Drupal\migrate\Entity\MigrationInterface;
use Drupal\migrate\Plugin\MigrateIdMapInterface;
/**
* Sources whose data may be fetched via DBTNG.
*/
abstract class SqlBase extends SourcePluginBase {
/**
* @var \Drupal\Core\Database\Query\SelectInterface
*/
protected $query;
/**
* @var \Drupal\migrate\Entity\MigrationInterface
*/
protected $migration;
/**
* @var \Drupal\Core\Database\Connection
*/
protected $database;
/**
* {@inheritdoc}
*/
function __construct(array $configuration, $plugin_id, array $plugin_definition, MigrationInterface $migration) {
parent::__construct($configuration, $plugin_id, $plugin_definition, $migration);
$this->mapJoinable = TRUE;
}
/**
* @return \Drupal\Core\Database\Connection
*/
function __toString() {
return (string) $this->query;
}
/**
* @return \Drupal\Core\Database\Connection
*/
public function getDatabase() {
if (!isset($this->database)) {
$this->database = static::getDatabaseConnection($this->migration->id(), $this->configuration);
}
return $this->database;
}
public static function getDatabaseConnection($id, array $configuration) {
if (isset($configuration['database'])) {
$key = 'migrate_' . $id;
Database::addConnectionInfo($key, 'default', $configuration['database']);
}
else {
$key = 'default';
}
return Database::getConnection('default', $key);
}
protected function select($table, $alias = NULL, array $options = array()) {
$options['fetch'] = \PDO::FETCH_ASSOC;
return $this->getDatabase()->select($table, $alias, $options);
}
/**
* Implementation of MigrateSource::performRewind().
*
* We could simply execute the query and be functionally correct, but
* we will take advantage of the PDO-based API to optimize the query up-front.
*/
protected function runQuery() {
$this->query = clone $this->query();
$this->query->addTag('migrate');
$this->query->addTag('migrate_' . $this->migration->id());
$this->query->addMetaData('migration', $this->migration);
$highwaterProperty = $this->migration->get('highwaterProperty');
// Get the key values, for potential use in joining to the map table, or
// enforcing idlist.
$keys = array();
foreach ($this->migration->get('sourceIds') as $field_name => $field_schema) {
if (isset($field_schema['alias'])) {
$field_name = $field_schema['alias'] . '.' . $field_name;
}
$keys[] = $field_name;
}
// The rules for determining what conditions to add to the query are as
// follows (applying first applicable rule)
// 1. If idlist is provided, then only process items in that list (AND key
// IN (idlist)). Only applicable with single-value keys.
if ($id_list = $this->migration->get('idlist')) {
$this->query->condition($keys[0], $id_list, 'IN');
}
else {
// 2. If the map is joinable, join it. We will want to accept all rows
// which are either not in the map, or marked in the map as NEEDS_UPDATE.
// Note that if highwater fields are in play, we want to accept all rows
// above the highwater mark in addition to those selected by the map
// conditions, so we need to OR them together (but AND with any existing
// conditions in the query). So, ultimately the SQL condition will look
// like (original conditions) AND (map IS NULL OR map needs update
// OR above highwater).
$conditions = $this->query->orConditionGroup();
$condition_added = FALSE;
if ($this->mapJoinable) {
// Build the join to the map table. Because the source key could have
// multiple fields, we need to build things up.
$count = 1;
$map_join = '';
$delimiter = '';
foreach ($this->migration->get('sourceIds') as $field_name => $field_schema) {
if (isset($field_schema['alias'])) {
$field_name = $field_schema['alias'] . '.' . $field_name;
}
$map_join .= "$delimiter$field_name = map.sourceid" . $count++;
$delimiter = ' AND ';
}
$alias = $this->query->leftJoin($this->migration->getIdMap()->getQualifiedMapTable(), 'map', $map_join);
$conditions->isNull($alias . '.sourceid1');
$conditions->condition($alias . '.needs_update', MigrateIdMapInterface::STATUS_NEEDS_UPDATE);
$condition_added = TRUE;
// And as long as we have the map table, add its data to the row.
$n = count($this->migration->get('sourceIds'));
for ($count = 1; $count <= $n; $count++) {
$map_key = 'sourceid' . $count;
$this->query->addField($alias, $map_key, "migrate_map_$map_key");
}
$n = count($this->migration->get('destinationIds'));
for ($count = 1; $count <= $n; $count++) {
$map_key = 'destid' . $count++;
$this->query->addField($alias, $map_key, "migrate_map_$map_key");
}
$this->query->addField($alias, 'needs_update', 'migrate_map_needs_update');
}
// 3. If we are using highwater marks, also include rows above the mark.
// But, include all rows if the highwater mark is not set.
if (isset($highwaterProperty['name']) && ($highwater = $this->migration->getHighwater()) !== '') {
if (isset($highwaterProperty['alias'])) {
$highwater = $highwaterProperty['alias'] . '.' . $highwaterProperty['name'];
}
else {
$highwater = $highwaterProperty['name'];
}
$conditions->condition($highwater, $highwater, '>');
$condition_added = TRUE;
}
if ($condition_added) {
$this->query->condition($conditions);
}
}
return new \IteratorIterator($this->query->execute());
}
/**
* @return \Drupal\Core\Database\Query\SelectInterface
*/
abstract function query();
/**
* {@inheritdoc}
*/
public function count() {
return $this->query()->countQuery()->execute()->fetchField();
}
/**
* Returns the iterator that will yield the row arrays to be processed.
*
* @return \Iterator
*/
public function getIterator() {
if (!isset($this->iterator)) {
$this->iterator = $this->runQuery();
}
return $this->iterator;
}
}
<?php
/**
* @file
* Contains \Drupal\migrate\Plugin\migrate\source\d6\Drupal6SqlBase.
*/
namespace Drupal\migrate\Plugin\migrate\source\d6;
use Drupal\migrate\Plugin\migrate\source\SqlBase;
/**
* A base source class for Drupal 6 migrate sources.
*
* Mainly to let children retrieve information from the origin system in an
* easier way.
*/
abstract class Drupal6SqlBase extends SqlBase {
/**
* Retrieves all system data information from origin system.
*
* @return array
* List of system table information keyed by type and name.
*/
public function getSystemData() {
static $system_data;
if (isset($system_data)) {
return $system_data;
}
$results = $this->database
->select('system', 's')
->fields('s')
->execute();
foreach ($results as $result) {
$system_data[$result['type']][$result['name']] = $result;
}
return $system_data;
}
/**
* Get a module schema_version value in the source installation.
*
* @param string $module
* Name of module.
*
* @return mixed
* The current module schema version on the origin system table or FALSE if
* not found.
*/
protected function getModuleSchemaVersion($module) {
$system_data = $this->getSystemData();
return isset($system_data['module'][$module]['schema_version']) ? $system_data['module'][$module]['schema_version'] : FALSE;
}
/**
* Check to see if a given module is enabled in the source installation.
*
* @param string $module
* Name of module to check.
*
* @return bool
* TRUE if module is enabled on the origin system, FALSE if not.
*/
protected function moduleExists($module) {
return isset($system_data['module'][$module]['status']) ? (bool) $system_data['module'][$module]['status'] : FALSE;
}
protected function variableGet($name, $default) {
try {
$result = $this->database
->query('SELECT value FROM {variable} WHERE name = :name', array(':name' => $name))
->fetchField();
}
// The table might not exist.
catch (\Exception $e) {
$result = FALSE;
}
return $result !== FALSE ? unserialize($result) : $default;
}
}
<?php
/**
* @file
* Contains \Drupal\migrate\Row.
*/
namespace Drupal\migrate;
use Drupal\Component\Utility\NestedArray;
use Drupal\migrate\Plugin\MigrateIdMapInterface;
/**
* Stores a row.
*/
class Row {
/**
* The actual values of the source row.
*
* @var array
*/
protected $source = array();
/**
* The source identifiers.
*
* @var array
*/
protected $sourceIds = array();
/**
* The destination values.
*
* @var array
*/
protected $destination = array();
/**
* The mapping between source and destination identifiers.
*
* @var array
*/
protected $idMap = array(
'original_hash' => '',
'hash' => '',
'needs_update' => MigrateIdMapInterface::STATUS_NEEDS_UPDATE,
);
/**
* Whether the source has been frozen already.
*
* Once frozen the source can not be changed any more.
*
* @var bool
*/
protected $frozen = FALSE;
/**
* Constructs a \Drupal\Migrate\Row object.
*
* @param array $values
* An array of values to add as properties on the object.
* @param array $source_ids
* An array containing the IDs of the source using the keys as the field
* names.
*
* @throws \InvalidArgumentException
* Thrown when a source ID property does not exist.
*/
public function __construct(array $values, array $source_ids) {
$this->source = $values;
$this->sourceIds = $source_ids;
foreach (array_keys($source_ids) as $id) {
if (!$this->hasSourceProperty($id)) {
throw new \InvalidArgumentException("$id has no value");
}
}
}
/**
* Retrieves the values of the source identifiers.
*
* @return array
* An array containing the values of the source identifiers.
*/
public function getSourceIdValues() {
return array_intersect_key($this->source, $this->sourceIds);
}
/**
* Determines whether a source has a property.
*
* @param string $property
* A property on the source.
*
* @return bool
* TRUE if the source has property; FALSE otherwise.
*/
public function hasSourceProperty($property) {
return isset($this->source[$property]) || array_key_exists($property, $this->source);
}
/**
* Retrieves a source property.
*
* @param string $property
* A property on the source.
*
* @return mixed|null
* The found returned property or NULL if not found.
*/
public function getSourceProperty($property) {
if (isset($this->source[$property])) {
return $this->source[$property];
}
}
/**
* Returns the whole source array.
*
* @return array
* An array of source plugins.
*/
public function getSource() {
return $this->source;
}
/**
* Sets a source property.
*
* This can only be called from the source plugin.
*
* @param string $property
* A property on the source.
* @param mixed $data
* The property value to set on the source.
*
* @throws \Exception
*/
public function setSourceProperty($property, $data) {
if ($this->frozen) {
throw new \Exception("The source is frozen and can't be changed any more");
}
else {
$this->source[$property] = $data;
}
}
/**
* Freezes the source.
*/
public function freezeSource() {
$this->frozen = TRUE;
}
/**
* Tests if destination property exists.
*
* @param array|string $property
* An array of properties on the destination.
*
* @return boolean
* TRUE if the destination property exists.
*/
public function hasDestinationProperty($property) {
return NestedArray::keyExists($this->destination, explode(':', $property));
}
/**
* Sets destination properties.
*
* @param string $property
* The name of the destination property.
* @param mixed $value
* The property value to set on the destination.
*/
public function setDestinationProperty($property, $value) {
NestedArray::setValue($this->destination, explode(':', $property), $value, TRUE);
}
/**
* Returns the whole destination array.
*
* @return array
* An array of destination values.
*/
public function getDestination() {
return $this->destination;
}
/**
* Returns the value of a destination property.
*
* @param array|string $property
* An array of properties on the destination.
*
* @return mixed
* The destination value.
*/
public function getDestinationProperty($property) {
return NestedArray::getValue($this->destination, explode(':', $property));
}
/**
* Sets the Migrate ID mappings.
*
* @param array $id_map
* An array of mappings between source ID and destination ID.
*/
public function setIdMap(array $id_map) {
$this->idMap = $id_map;
}
/**
* Retrieves the Migrate ID mappings.
*
* @return array
* An array of mapping between source and destination identifiers.
*/
public function getIdMap() {
return $this->idMap;
}
/**
* Recalculates the hash for the row.
*/
public function rehash() {
$this->idMap['original_hash'] = $this->idMap['hash'];
$this->idMap['hash'] = hash('sha256', serialize($this->source));
}
/**
* Checks whether the row has changed compared to the original ID map.
*
* @return bool
* TRUE if the row has changed, FALSE otherwise. If setIdMap() was not
* called, this always returns FALSE.
*/
public function changed() {
return $this->idMap['original_hash'] != $this->idMap['hash'];
}
/**
* Returns if this row needs an update.
*
* @return bool
* TRUE if the row needs updating, FALSE otherwise.
*/
public function needsUpdate() {
return $this->idMap['needs_update'] == MigrateIdMapInterface::STATUS_NEEDS_UPDATE;
}
/**
* Returns the hash for the source values..
*
* @return mixed
* The hash of the source values.
*/
public function getHash() {
return $this->idMap['hash'];
}
}
<?php
/**
* @file
* Contains \Drupal\migrate\Plugin\migrate\source\SourceBase.
*/
namespace Drupal\migrate;
use Drupal\migrate\Entity\MigrationInterface;
use Drupal\migrate\Plugin\MigrateIdMapInterface;
/**
* Source is a caching / decision making wrapper around the source plugin.
*
* Derived classes are expected to define __toString(), returning a string
* describing the source and significant options, i.e. the query.
*
* @see \Drupal\migrate\MigrateSourceInterface
*/
class Source implements \Iterator, \Countable {
/**
* The current row from the quey
*
* @var \Drupal\Migrate\Row
*/
protected $currentRow;
/**
* The primary key of the current row
*
* @var array
*/
protected $currentIds;
/**
* Number of rows intentionally ignored (prepareRow() returned FALSE)
*
* @var int
*/
protected $numIgnored = 0;
/**
* Number of rows we've at least looked at.
*
* @var int
*/
protected $numProcessed = 0;
/**
* The highwater mark at the beginning of the import operation.
*
* @var
*/
protected $originalHighwater = '';
/**
* List of source IDs to process.
*
* @var array
*/
protected $idList = array();
/**
* Whether this instance should cache the source count.
*
* @var boolean
*/
protected $cacheCounts = FALSE;
/**
* Key to use for caching counts.
*
* @var string
*/
protected $cacheKey;
/**
* Whether this instance should not attempt to count the source.
*
* @var boolean
*/
protected $skipCount = FALSE;
/**
* If TRUE, we will maintain hashed source rows to determine whether incoming
* data has changed.
*
* @var bool
*/
protected $trackChanges = FALSE;
/**
* By default, next() will directly read the map row and add it to the data
* row. A source plugin implementation may do this itself (in particular, the
* SQL source can incorporate the map table into the query) - if so, it should
* set this TRUE so we don't duplicate the effort.
*
* @var bool
*/
protected $mapRowAdded = FALSE;
/**
* @var array
*/
protected $sourceIds;
/**
* @var \Drupal\Core\Cache\CacheBackendInterface
*/
protected $cache;
/**
* @var \Drupal\migrate\Plugin\MigrateIdMapInterface
*/
protected $idMap;
/**
* @var array
*/
protected $highwaterProperty;
public function getCurrentIds() {
return $this->currentIds;
}
public function getIgnored() {
return $this->numIgnored;
}
public function getProcessed() {
return $this->numProcessed;
}
/**
* Reset numIgnored back to 0.
*/
public function resetStats() {
$this->numIgnored = 0;
}
/**
* Return a count of available source records, from the cache if appropriate.
* Returns -1 if the source is not countable.
*
* @param boolean $refresh
* @return int
*/
public function count($refresh = FALSE) {
if ($this->skipCount) {
return -1;
}
$source = $this->migration->getSourcePlugin();
if (!isset($this->cacheKey)) {
$this->cacheKey = hash('sha256', (string) $source);
}
// If a refresh is requested, or we're not caching counts, ask the derived
// class to get the count from the source.
if ($refresh || !$this->cacheCounts) {
$count = $source->count();
$this->cache->set($this->cacheKey, $count, 'cache');
}
else {
// Caching is in play, first try to retrieve a cached count.
$cache_object = $this->cache->get($this->cacheKey, 'cache');
if (is_object($cache_object)) {
// Success
$count = $cache_object->data;
}
else {
// No cached count, ask the derived class to count 'em up, and cache
// the result
$count = $source->count();
$this->cache->set($this->cacheKey, $count, 'cache');
}
}
return $count;
}
/**
* Class constructor.
*
* @param \Drupal\migrate\Entity\MigrationInterface $migration
* @param \Drupal\migrate\MigrateExecutable $migrate_executable
*/
function __construct(MigrationInterface $migration, MigrateExecutable $migrate_executable) {
$this->migration = $migration;
$this->migrateExecutable = $migrate_executable;
$configuration = $migration->get('source');
if (!empty($configuration['cache_counts'])) {
$this->cacheCounts = TRUE;
}
if (!empty($configuration['skip_count'])) {
$this->skipCount = TRUE;
}
if (!empty($configuration['cache_key'])) {
$this->cacheKey = $configuration['cache_key'];
}
if (!empty($configuration['track_changes'])) {
$this->trackChanges = $configuration['track_changes'];
}
}
/**
* @return \Drupal\Core\Cache\CacheBackendInterface
*/
protected function getCache() {
if (!isset($this->cache)) {
$this->cache = \Drupal::cache('migrate');
}
return $this->cache;
}
/**
* @return \Iterator
*/
protected function getIterator() {
if (!isset($this->iterator)) {
$this->iterator = $this->migration->getSourcePlugin()->getIterator();
}
return $this->iterator;
}
/**
* {@inheritdoc}
*/
public function current() {
return $this->currentRow;
}
/**
* 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 getCurrentIds() is preferable.
*/
public function key() {
return serialize($this->currentIds);
}
/**
* 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 isset($this->currentRow);
}
/**
* Implementation of Iterator::rewind() - subclasses of MigrateSource should
* implement performRewind() to do any class-specific setup for iterating
* source records.
*/
public function rewind() {
$this->idMap = $this->migration->getIdMap();
$this->numProcessed = 0;
$this->numIgnored = 0;
$this->originalHighwater = $this->migration->getHighwater();
$this->highwaterProperty = $this->migration->get('highwaterProperty');
if ($id_list = $this->migration->get('idlist')) {
$this->idList = $id_list;
}
$this->getIterator()->rewind();
$this->next();
}
/**
* {@inheritdoc}
*/
public function next() {
$this->currentIds = NULL;
$this->currentRow = NULL;
while ($this->getIterator()->valid()) {
$row_data = $this->getIterator()->current();
$this->getIterator()->next();
$row = new Row($row_data, $this->migration->get('sourceIds'), $this->migration->get('destinationIds'));
// Populate the source key for this row
$this->currentIds = $row->getSourceIdValues();
// Pick up the existing map row, if any, unless getNextRow() did it.
if (!$this->mapRowAdded && ($id_map = $this->idMap->getRowBySource($this->currentIds))) {
$row->setIdMap($id_map);
}
// First, determine if this row should be passed to prepareRow(), or
// skipped entirely. The rules are:
// 1. If there's an explicit idlist, that's all we care about (ignore
// highwaters and map rows).
$prepared = FALSE;
if (!empty($this->idList)) {
if (in_array(reset($this->currentIds), $this->idList)) {
// In the list, fall through.
}
else {
// Not in the list, skip it
continue;
}
}
// 2. If the row is not in the map (we have never tried to import it
// before), we always want to try it.
elseif (!$row->getIdMap()) {
// Fall through
}
// 3. If the row is marked as needing update, pass it.
elseif ($row->needsUpdate()) {
// Fall through
}
// 4. At this point, we have a row which has previously been imported and
// not marked for update. If we're not using highwater marks, then we
// will not take this row. Except, if we're looking for changes in the
// data, we need to go through prepareRow() before we can decide to
// skip it.
elseif (!empty($highwater['field'])) {
if ($this->trackChanges) {
if ($this->prepareRow($row) !== FALSE) {
if ($row->changed()) {
// This is a keeper
$this->currentRow = $row;
break;
}
else {
// No change, skip it.
continue;
}
}
else {
// prepareRow() told us to skip it.
continue;
}
}
else {
// No highwater and not tracking changes, skip.
continue;
}
}
// 5. The initial highwater mark, before anything is migrated, is ''. We
// want to make sure we don't mistakenly skip rows with a highwater
// field value of 0, so explicitly handle '' here.
elseif ($this->originalHighwater === '') {
// Fall through
}
// 6. So, we are using highwater marks. Take the row if its highwater
// field value is greater than the saved mark, otherwise skip it.
else {
// Call prepareRow() here, in case the highwaterField needs preparation
if ($this->prepareRow($row) !== FALSE) {
if ($row->getSourceProperty($this->highwaterProperty['name']) > $this->originalHighwater) {
$this->currentRow = $row;
break;
}
else {
// Skip
continue;
}
}
$prepared = TRUE;
}
// Allow the Migration to prepare this row. prepareRow() can return boolean
// FALSE to ignore this row.
if (!$prepared) {
if ($this->prepareRow($row) !== FALSE) {
// Finally, we've got a keeper.
$this->currentRow = $row;
break;
}
else {
$this->currentRow = NULL;
}
}
}
if ($this->currentRow) {
$this->currentRow->freezeSource();
}
else {
$this->currentIds = NULL;
}
}
/**
* Source classes should override this as necessary and manipulate $keep.
*
* @param \Drupal\migrate\Row $row
*/
protected function prepareRow(Row $row) {
// We're explicitly skipping this row - keep track in the map table
if ($this->migration->getSourcePlugin()->prepareRow($row) === FALSE) {
// Make sure we replace any previous messages for this item with any
// new ones.
$id_map = $this->migration->getIdMap();
$id_map->delete($this->currentIds, TRUE);
$this->migrateExecutable->saveQueuedMessages();
$id_map->saveIdMapping($row, array(), MigrateIdMapInterface::STATUS_IGNORED, $this->migrateExecutable->rollbackAction);
$this->numIgnored++;
$this->currentRow = NULL;
$this->currentIds = NULL;
}
else {
// When tracking changed data, We want to quietly skip (rather than
// "ignore") rows with changes. The caller needs to make that decision,
// so we need to provide them with the necessary information (before and
// after hashes).
if ($this->trackChanges) {
$row->rehash();
}
}
$this->numProcessed++;
}
}
<?php
/**
* @file
* Contains \Drupal\migrate\Tests\Drupal6SystemCron.
*/
namespace Drupal\migrate\Tests\Dump;
use Drupal\Core\Database\Connection;
/**
* Database dump for testing system.cron.yml migration.
*/
class Drupal6SystemCron {
/**
* Sample database schema and values.
*
* @param \Drupal\Core\Database\Connection $database
* The database connection.
*/
public static function load(Connection $database) {
$database->schema()->createTable('variable', array(
'fields' => array(
'name' => array(
'type' => 'varchar',
'length' => 128,
'not null' => TRUE,
'default' => '',
),
'value' => array(
'type' => 'blob',
'not null' => TRUE,
'size' => 'big',
'translatable' => TRUE,
),
),
'primary key' => array(
'name',
),
'module' => 'system',
'name' => 'variable',
));
$database->insert('variable')->fields(array(
'name',
'value',
))
->values(array(
'name' => 'cron_threshold_warning',
'value' => 'i:172800;',
))
->values(array(
'name' => 'cron_threshold_error',
'value' => 'i:1209600;',
))
->execute();
}
}
<?php
/**
* @file
* Contains \Drupal\migrate\Tests\Drupal6SystemRss.
*/
namespace Drupal\migrate\Tests\Dump;
use Drupal\Core\Database\Connection;
/**
* Database dump for testing system.settings.yml migration.
*/
class Drupal6SystemRss {
/**
* Sample database schema and values.
*
* @param \Drupal\Core\Database\Connection $database
* The database connection.
*/
public static function load(Connection $database) {
$database->schema()->createTable('variable', array(
'fields' => array(
'name' => array(
'type' => 'varchar',
'length' => 128,
'not null' => TRUE,
'default' => '',
),
'value' => array(
'type' => 'blob',
'not null' => TRUE,
'size' => 'big',
'translatable' => TRUE,
),
),
'primary key' => array(
'name',
),
'module' => 'system',
'name' => 'variable',
));
$database->insert('variable')->fields(array(
'name',
'value',
))
->values(array(
'name' => 'feed_default_items',
'value' => 'i:10;',
))
->execute();
}
}
<?php
namespace Drupal\migrate\Tests\Dump;
use Drupal\Core\Database\Connection;
/**
* Database dump for testing system.site.yml migration.
*/
class Drupal6SystemSite {
/**
* @param \Drupal\Core\Database\Connection $database
*/
public static function load(Connection $database) {
$database->schema()->createTable('variable', array(
'fields' => array(
'name' => array(
'type' => 'varchar',
'length' => 128,
'not null' => TRUE,
'default' => '',
),
'value' => array(
'type' => 'blob',
'not null' => TRUE,
'size' => 'big',
'translatable' => TRUE,
),
),
'primary key' => array(
'name',
),
'module' => 'system',
'name' => 'variable',
));
$database->insert('variable')->fields(array(
'name',
'value',
))
->values(array(
'name' => 'site_name',
'value' => 's:6:"drupal";',
))
->values(array(
'name' => 'site_mail',
'value' => 's:17:"admin@example.com";',
))
->values(array(
'name' => 'site_slogan',
'value' => 's:13:"Migrate rocks";',
))
->values(array(
'name' => 'site_frontpage',
'value' => 's:12:"anonymous-hp";',
))
->values(array(
'name' => 'site_403',
'value' => 's:4:"user";',
))
->values(array(
'name' => 'site_404',
'value' => 's:14:"page-not-found";',
))
->values(array(
'name' => 'drupal_weight_select_max',
'value' => 'i:99;',
))
->values(array(
'name' => 'admin_compact_mode',
'value' => 'b:0;',
))
->execute();
}
}
<?php
use Drupal\migrate\Entity\MigrationInterface;
use Drupal\migrate\Plugin\MigrateSourceInterface;
use Drupal\migrate\Row;
/**
* @file
* Hooks provided by the Migrate module.
*/
/**
* @addtogroup hooks
* @{
*/
/**
* Allows adding data to a row before processing it.
*
* For example, filter module used to store filter format settings in the
* variables table which now needs to be inside the filter format config
* file. So, it needs to be added here.
*
* hook_migrate_MIGRATION_ID_prepare_row is also available.
*/
function hook_migrate_prepare_row(Row $row, MigrateSourceInterface $source, MigrationInterface $migration) {
if ($migration->id() == 'drupal6_filter_formats') {
$value = $source->getDatabase()->query('SELECT value FROM {variable} WHERE name = :name', array(':name' => 'mymodule_filter_foo_' . $row->getSourceProperty('format')))->fetchField();
if ($value) {
$row->setSourceProperty('settings:mymodule:foo', unserialize($value));
}
}
}
/**
* @} End of "addtogroup hooks".
*/
This diff is collapsed.
This diff is collapsed.