Drupal 8.0.0 beta 12. More info: https://www.drupal.org/node/2514176
This commit is contained in:
commit
9921556621
13277 changed files with 1459781 additions and 0 deletions
77
core/modules/migrate/src/Plugin/Derivative/MigrateEntity.php
Normal file
77
core/modules/migrate/src/Plugin/Derivative/MigrateEntity.php
Normal file
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\Derivative\MigrateEntity.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin\Derivative;
|
||||
|
||||
use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
class MigrateEntity implements ContainerDeriverInterface {
|
||||
|
||||
/**
|
||||
* List of derivative definitions.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $derivatives = array();
|
||||
|
||||
/**
|
||||
* The entity definitions
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeInterface[]
|
||||
*/
|
||||
protected $entityDefinitions;
|
||||
|
||||
/**
|
||||
* Constructs a MigrateEntity object.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityTypeInterface[] $entity_definitions
|
||||
* A list of entity definition objects.
|
||||
*/
|
||||
public function __construct(array $entity_definitions) {
|
||||
$this->entityDefinitions = $entity_definitions;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, $base_plugin_id) {
|
||||
return new static(
|
||||
$container->get('entity.manager')->getDefinitions()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDerivativeDefinition($derivative_id, $base_plugin_definition) {
|
||||
if (!empty($this->derivatives) && !empty($this->derivatives[$derivative_id])) {
|
||||
return $this->derivatives[$derivative_id];
|
||||
}
|
||||
$this->getDerivativeDefinitions($base_plugin_definition);
|
||||
return $this->derivatives[$derivative_id];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDerivativeDefinitions($base_plugin_definition) {
|
||||
foreach ($this->entityDefinitions as $entity_type => $entity_info) {
|
||||
$class = is_subclass_of($entity_info->getClass(), 'Drupal\Core\Config\Entity\ConfigEntityInterface') ?
|
||||
'Drupal\migrate\Plugin\migrate\destination\EntityConfigBase' :
|
||||
'Drupal\migrate\Plugin\migrate\destination\EntityContentBase';
|
||||
$this->derivatives[$entity_type] = array(
|
||||
'id' => "entity:$entity_type",
|
||||
'class' => $class,
|
||||
'requirements_met' => 1,
|
||||
'provider' => $entity_info->getProvider(),
|
||||
);
|
||||
}
|
||||
return $this->derivatives;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\Derivative\MigrateEntityRevision.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin\Derivative;
|
||||
|
||||
use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
class MigrateEntityRevision implements ContainerDeriverInterface {
|
||||
|
||||
/**
|
||||
* List of derivative definitions.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $derivatives = array();
|
||||
|
||||
/**
|
||||
* The entity definitions
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeInterface[]
|
||||
*/
|
||||
protected $entityDefinitions;
|
||||
|
||||
/**
|
||||
* Constructs a MigrateEntity object.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityTypeInterface[] $entity_definitions
|
||||
* A list of entity definition objects.
|
||||
*/
|
||||
public function __construct(array $entity_definitions) {
|
||||
$this->entityDefinitions = $entity_definitions;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, $base_plugin_id) {
|
||||
return new static(
|
||||
$container->get('entity.manager')->getDefinitions()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDerivativeDefinition($derivative_id, $base_plugin_definition) {
|
||||
if (!empty($this->derivatives) && !empty($this->derivatives[$derivative_id])) {
|
||||
return $this->derivatives[$derivative_id];
|
||||
}
|
||||
$this->getDerivativeDefinitions($base_plugin_definition);
|
||||
return $this->derivatives[$derivative_id];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDerivativeDefinitions($base_plugin_definition) {
|
||||
foreach ($this->entityDefinitions as $entity_type => $entity_info) {
|
||||
if ($entity_info->getKey('revision')) {
|
||||
$this->derivatives[$entity_type] = array(
|
||||
'id' => "entity_revision:$entity_type",
|
||||
'class' => 'Drupal\migrate\Plugin\migrate\destination\EntityRevision',
|
||||
'requirements_met' => 1,
|
||||
'provider' => $entity_info->getProvider(),
|
||||
);
|
||||
}
|
||||
}
|
||||
return $this->derivatives;
|
||||
}
|
||||
|
||||
}
|
109
core/modules/migrate/src/Plugin/MigrateDestinationInterface.php
Normal file
109
core/modules/migrate/src/Plugin/MigrateDestinationInterface.php
Normal file
|
@ -0,0 +1,109 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\MigrateDestinationInterface.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin;
|
||||
|
||||
use Drupal\Component\Plugin\PluginInspectionInterface;
|
||||
use Drupal\migrate\Entity\MigrationInterface;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* Destinations are responsible for persisting source data into the destination
|
||||
* Drupal.
|
||||
*
|
||||
* @see \Drupal\migrate\Plugin\destination\DestinationBase
|
||||
* @see \Drupal\migrate\Plugin\MigrateDestinationPluginManager
|
||||
* @see \Drupal\migrate\Annotation\MigrateDestination
|
||||
* @see plugin_api
|
||||
*
|
||||
* @ingroup migration
|
||||
*/
|
||||
interface MigrateDestinationInterface extends PluginInspectionInterface {
|
||||
|
||||
/**
|
||||
* Get the destination ids.
|
||||
*
|
||||
* To support MigrateIdMap 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.
|
||||
*
|
||||
* @return array
|
||||
* An array of ids.
|
||||
*/
|
||||
public function getIds();
|
||||
|
||||
/**
|
||||
* Returns an array of destination fields.
|
||||
*
|
||||
* Derived classes must implement fields(), returning a list of available
|
||||
* destination fields.
|
||||
*
|
||||
* @todo Review the cases where we need the Migration parameter,
|
||||
* can we avoid that?
|
||||
*
|
||||
* @param \Drupal\migrate\Entity\MigrationInterface $migration
|
||||
* (optional) the migration containing this destination.
|
||||
*
|
||||
* @return array
|
||||
* - Keys: machine names of the fields
|
||||
* - Values: Human-friendly descriptions of the fields.
|
||||
*/
|
||||
public function fields(MigrationInterface $migration = NULL);
|
||||
|
||||
|
||||
/**
|
||||
* Allows pre-processing of an import.
|
||||
*
|
||||
* Derived classes may implement preImport() to do any processing they need
|
||||
* done before over all source rows.
|
||||
*/
|
||||
public function preImport();
|
||||
|
||||
/**
|
||||
* Allows pre-processing of a rollback.
|
||||
*/
|
||||
public function preRollback();
|
||||
|
||||
/**
|
||||
* Allows post-processing of an import.
|
||||
*
|
||||
* Derived classes may implement postImport(), to do any processing they need
|
||||
* done after looping over all source rows.
|
||||
*/
|
||||
public function postImport();
|
||||
|
||||
/**
|
||||
* Allows post-processing of a rollback.
|
||||
*/
|
||||
public function postRollback();
|
||||
|
||||
/**
|
||||
* Import the row.
|
||||
*
|
||||
* Derived classes must implement import(), to construct one new object
|
||||
* (pre-populated) using ID mappings in the Migration).
|
||||
*
|
||||
* @param \Drupal\migrate\Row $row
|
||||
* The row object.
|
||||
* @param array $old_destination_id_values
|
||||
* The old destination ids.
|
||||
*
|
||||
* @return mixed
|
||||
* The entity id or an indication of success.
|
||||
*/
|
||||
public function import(Row $row, array $old_destination_id_values = array());
|
||||
|
||||
/**
|
||||
* Delete the specified IDs from the target Drupal.
|
||||
*
|
||||
* @param array $destination_identifiers
|
||||
* The destination ids to delete.
|
||||
*/
|
||||
public function rollbackMultiple(array $destination_identifiers);
|
||||
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\MigrateDestinationPluginManager.
|
||||
*/
|
||||
|
||||
|
||||
namespace Drupal\migrate\Plugin;
|
||||
|
||||
use Drupal\Core\Cache\CacheBackendInterface;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\migrate\Entity\MigrationInterface;
|
||||
|
||||
/**
|
||||
* Plugin manager for migrate destination plugins.
|
||||
*
|
||||
* @see \Drupal\migrate\Plugin\MigrateDestinationInterface
|
||||
* @see \Drupal\migrate\Plugin\destination\DestinationBase
|
||||
* @see \Drupal\migrate\Annotation\MigrateDestination
|
||||
* @see plugin_api
|
||||
*
|
||||
* @ingroup migration
|
||||
*/
|
||||
class MigrateDestinationPluginManager extends MigratePluginManager {
|
||||
|
||||
/**
|
||||
* The theme handler
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ThemeHandlerInterface
|
||||
*/
|
||||
protected $themeHandler;
|
||||
|
||||
/**
|
||||
* An associative array where the keys are the enabled modules and themes.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $providers;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct($type, \Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, EntityManagerInterface $entity_manager, $annotation = 'Drupal\migrate\Annotation\MigrateDestination') {
|
||||
parent::__construct($type, $namespaces, $cache_backend, $module_handler, $annotation);
|
||||
$this->entityManager = $entity_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* A specific createInstance method is necessary to pass the migration on.
|
||||
*/
|
||||
public function createInstance($plugin_id, array $configuration = array(), MigrationInterface $migration = NULL) {
|
||||
if (substr($plugin_id, 0, 7) == 'entity:' && !$this->entityManager->getDefinition(substr($plugin_id, 7), FALSE)) {
|
||||
$plugin_id = 'null';
|
||||
}
|
||||
return parent::createInstance($plugin_id, $configuration, $migration);
|
||||
}
|
||||
|
||||
}
|
242
core/modules/migrate/src/Plugin/MigrateIdMapInterface.php
Normal file
242
core/modules/migrate/src/Plugin/MigrateIdMapInterface.php
Normal file
|
@ -0,0 +1,242 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\MigrateIdMapInterface.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin;
|
||||
|
||||
use Drupal\Component\Plugin\PluginInspectionInterface;
|
||||
use Drupal\migrate\Entity\MigrationInterface;
|
||||
use Drupal\migrate\MigrateMessageInterface;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* Defines an interface for migrate ID mappings.
|
||||
*
|
||||
* Migrate ID mappings maintain a relation between source ID and destination ID
|
||||
* for audit and rollback purposes.
|
||||
*/
|
||||
interface MigrateIdMapInterface extends \Iterator, PluginInspectionInterface {
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Codes reflecting how to handle the destination item on rollback.
|
||||
*/
|
||||
const ROLLBACK_DELETE = 0;
|
||||
const ROLLBACK_PRESERVE = 1;
|
||||
|
||||
/**
|
||||
* Saves a mapping from the source identifiers to the destination identifiers.
|
||||
*
|
||||
* Called upon import of one row, we record a mapping from the source ID
|
||||
* to the destination ID. Also may be called, setting the third parameter to
|
||||
* NEEDS_UPDATE, to signal an existing record should be re-migrated.
|
||||
*
|
||||
* @param \Drupal\migrate\Row $row
|
||||
* The raw source data. We use the ID map derived from the source object
|
||||
* to get the source identifier values.
|
||||
* @param array $destination_id_values
|
||||
* An array of destination identifier values.
|
||||
* @param int $status
|
||||
* Status of the source row in the map.
|
||||
* @param int $rollback_action
|
||||
* How to handle the destination object on rollback.
|
||||
*/
|
||||
public function saveIdMapping(Row $row, array $destination_id_values, $status = self::STATUS_IMPORTED, $rollback_action = self::ROLLBACK_DELETE);
|
||||
|
||||
/**
|
||||
* Saves a message related to a source record in the migration message table.
|
||||
*
|
||||
* @param array $source_id_values
|
||||
* The source identifier values of the record in error.
|
||||
* @param string $message
|
||||
* The message to record.
|
||||
* @param int $level
|
||||
* Optional message severity (defaults to MESSAGE_ERROR).
|
||||
*/
|
||||
public function saveMessage(array $source_id_values, $message, $level = MigrationInterface::MESSAGE_ERROR);
|
||||
|
||||
/**
|
||||
* Prepares to run a full update.
|
||||
*
|
||||
* Prepares this migration to run as an update - that is, in addition to
|
||||
* unmigrated content (source records not in the map table) being imported,
|
||||
* previously-migrated content will also be updated in place by marking all
|
||||
* previously-imported content as ready to be re-imported.
|
||||
*/
|
||||
public function prepareUpdate();
|
||||
|
||||
/**
|
||||
* Returns the number of processed items in the map.
|
||||
*
|
||||
* @return int
|
||||
* The count of records in the map table.
|
||||
*/
|
||||
public function processedCount();
|
||||
|
||||
/**
|
||||
* Returns the number of imported items in the map.
|
||||
*
|
||||
* @return int
|
||||
* The number of imported items.
|
||||
*/
|
||||
public function importedCount();
|
||||
|
||||
|
||||
/**
|
||||
* Returns a count of items which are marked as needing update.
|
||||
*
|
||||
* @return int
|
||||
* The number of items which need updating.
|
||||
*/
|
||||
public function updateCount();
|
||||
|
||||
/**
|
||||
* Returns the number of items that failed to import.
|
||||
*
|
||||
* @return int
|
||||
* The number of items that errored out.
|
||||
*/
|
||||
public function errorCount();
|
||||
|
||||
/**
|
||||
* Returns the number of messages saved.
|
||||
*
|
||||
* @return int
|
||||
* The number of messages.
|
||||
*/
|
||||
public function messageCount();
|
||||
|
||||
/**
|
||||
* Deletes the map and message entries for a given source record.
|
||||
*
|
||||
* @param array $source_id_values
|
||||
* The source identifier values of the record to delete.
|
||||
* @param bool $messages_only
|
||||
* TRUE to only delete the migrate messages.
|
||||
*/
|
||||
public function delete(array $source_id_values, $messages_only = FALSE);
|
||||
|
||||
/**
|
||||
* Deletes the map and message table entries for a given destination row.
|
||||
*
|
||||
* @param array $destination_id_values
|
||||
* The destination identifier values we should do the deletes for.
|
||||
*/
|
||||
public function deleteDestination(array $destination_id_values);
|
||||
|
||||
/**
|
||||
* Deletes the map and message entries for a set of given source records.
|
||||
*
|
||||
* @param array $source_id_values
|
||||
* The identifier values of the sources we should do the deletes for. Each
|
||||
* array member is an array of identifier values for one source row.
|
||||
*/
|
||||
public function deleteBulk(array $source_id_values);
|
||||
|
||||
/**
|
||||
* Clears all messages from the map.
|
||||
*/
|
||||
public function clearMessages();
|
||||
|
||||
/**
|
||||
* Retrieves a row from the map table based on source identifier values.
|
||||
*
|
||||
* @param array $source_id_values
|
||||
* The source identifier values of the record to retrieve.
|
||||
*
|
||||
* @return array
|
||||
* The raw row data as an associative array.
|
||||
*/
|
||||
public function getRowBySource(array $source_id_values);
|
||||
|
||||
/**
|
||||
* Retrieves a row by the destination identifiers.
|
||||
*
|
||||
* @param array $destination_id_values
|
||||
* The destination identifier values of the record to retrieve.
|
||||
*
|
||||
* @return array
|
||||
* The row(s) of data.
|
||||
*/
|
||||
public function getRowByDestination(array $destination_id_values);
|
||||
|
||||
/**
|
||||
* Retrieves an array of map rows marked as needing update.
|
||||
*
|
||||
* @param int $count
|
||||
* The maximum number of rows to return.
|
||||
*
|
||||
* @return array
|
||||
* Array of map row objects that need updating.
|
||||
*/
|
||||
public function getRowsNeedingUpdate($count);
|
||||
|
||||
/**
|
||||
* Looks up the source identifier.
|
||||
*
|
||||
* Given a (possibly multi-field) destination identifier value, return the
|
||||
* (possibly multi-field) source identifier value mapped to it.
|
||||
*
|
||||
* @param array $destination_id_values
|
||||
* The destination identifier values of the record.
|
||||
*
|
||||
* @return array
|
||||
* The source identifier values of the record, or NULL on failure.
|
||||
*/
|
||||
public function lookupSourceID(array $destination_id_values);
|
||||
|
||||
/**
|
||||
* Looks up the destination identifier.
|
||||
*
|
||||
* Given a (possibly multi-field) source identifier value, return the
|
||||
* (possibly multi-field) destination identifier value it is mapped to.
|
||||
*
|
||||
* @param array $source_id_values
|
||||
* The source identifier values of the record.
|
||||
*
|
||||
* @return array
|
||||
* The destination identifier values of the record, or NULL on failure.
|
||||
*/
|
||||
public function lookupDestinationId(array $source_id_values);
|
||||
|
||||
/**
|
||||
* Removes any persistent storage used by this map.
|
||||
*
|
||||
* For example, remove the map and message tables.
|
||||
*/
|
||||
public function destroy();
|
||||
|
||||
/**
|
||||
* Gets the qualified map table.
|
||||
*
|
||||
* @todo Remove this as this is SQL only and so doesn't belong to the interface.
|
||||
*/
|
||||
public function getQualifiedMapTableName();
|
||||
|
||||
/**
|
||||
* Sets the migrate message.
|
||||
*
|
||||
* @param \Drupal\migrate\MigrateMessageInterface $message
|
||||
* The message to display.
|
||||
*/
|
||||
public function setMessage(MigrateMessageInterface $message);
|
||||
|
||||
/**
|
||||
* Sets a specified record to be updated, if it exists.
|
||||
*
|
||||
* @param array $source_id_values
|
||||
* The source identifier values of the record.
|
||||
*/
|
||||
public function setUpdate(array $source_id_values);
|
||||
|
||||
}
|
89
core/modules/migrate/src/Plugin/MigratePluginManager.php
Normal file
89
core/modules/migrate/src/Plugin/MigratePluginManager.php
Normal file
|
@ -0,0 +1,89 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\MigratePluginManager.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin;
|
||||
|
||||
use Drupal\Component\Plugin\Factory\DefaultFactory;
|
||||
use Drupal\Core\Cache\CacheBackendInterface;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Plugin\DefaultPluginManager;
|
||||
use Drupal\migrate\Entity\MigrationInterface;
|
||||
|
||||
/**
|
||||
* Manages migrate plugins.
|
||||
*
|
||||
* @see hook_migrate_info_alter()
|
||||
* @see \Drupal\migrate\Annotation\MigrateSource
|
||||
* @see \Drupal\migrate\Plugin\MigrateSourceInterface
|
||||
* @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
|
||||
* @see \Drupal\migrate\Annotation\MigrateProcessPlugin
|
||||
* @see \Drupal\migrate\Plugin\MigrateProcessInterface
|
||||
* @see \Drupal\migrate\Plugin\migrate\process\ProcessPluginBase
|
||||
* @see plugin_api
|
||||
*
|
||||
* @ingroup migration
|
||||
*/
|
||||
class MigratePluginManager extends DefaultPluginManager {
|
||||
|
||||
/**
|
||||
* Constructs a MigratePluginManager object.
|
||||
*
|
||||
* @param string $type
|
||||
* The type of the plugin: row, source, process, destination, entity_field,
|
||||
* id_map.
|
||||
* @param \Traversable $namespaces
|
||||
* An object that implements \Traversable which contains the root paths
|
||||
* keyed by the corresponding namespace to look for plugin implementations.
|
||||
* @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
|
||||
* Cache backend instance to use.
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
|
||||
* The module handler to invoke the alter hook with.
|
||||
* @param string $annotation
|
||||
* The annotation class name.
|
||||
*/
|
||||
public function __construct($type, \Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, $annotation = 'Drupal\Component\Annotation\PluginID') {
|
||||
$plugin_interface = isset($plugin_interface_map[$type]) ? $plugin_interface_map[$type] : NULL;
|
||||
parent::__construct("Plugin/migrate/$type", $namespaces, $module_handler, $plugin_interface, $annotation);
|
||||
$this->alterInfo('migrate_' . $type . '_info');
|
||||
$this->setCacheBackend($cache_backend, 'migrate_plugins_' . $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* A specific createInstance method is necessary to pass the migration on.
|
||||
*/
|
||||
public function createInstance($plugin_id, array $configuration = array(), MigrationInterface $migration = NULL) {
|
||||
$plugin_definition = $this->getDefinition($plugin_id);
|
||||
$plugin_class = DefaultFactory::getPluginClass($plugin_id, $plugin_definition);
|
||||
// If the plugin provides a factory method, pass the container to it.
|
||||
if (is_subclass_of($plugin_class, 'Drupal\Core\Plugin\ContainerFactoryPluginInterface')) {
|
||||
$plugin = $plugin_class::create(\Drupal::getContainer(), $configuration, $plugin_id, $plugin_definition, $migration);
|
||||
}
|
||||
else {
|
||||
$plugin = new $plugin_class($configuration, $plugin_id, $plugin_definition, $migration);
|
||||
}
|
||||
return $plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for the plugin type to interface map.
|
||||
*
|
||||
* @return array
|
||||
* An array map from plugin type to interface.
|
||||
*/
|
||||
protected function getPluginInterfaceMap() {
|
||||
return [
|
||||
'destination' => 'Drupal\migrate\Plugin\MigrateDestinationInterface',
|
||||
'process' => 'Drupal\migrate\Plugin\MigrateProcessInterface',
|
||||
'source' => 'Drupal\migrate\Plugin\MigrateSourceInterface',
|
||||
'id_map' => 'Drupal\migrate\Plugin\MigrateIdMapInterface',
|
||||
'entity_field' => 'Drupal\migrate\Plugin\MigrateEntityDestinationFieldInterface',
|
||||
];
|
||||
}
|
||||
|
||||
}
|
62
core/modules/migrate/src/Plugin/MigrateProcessInterface.php
Normal file
62
core/modules/migrate/src/Plugin/MigrateProcessInterface.php
Normal file
|
@ -0,0 +1,62 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\MigrateProcessInterface.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin;
|
||||
|
||||
use Drupal\Component\Plugin\PluginInspectionInterface;
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* An interface for migrate process plugins.
|
||||
*
|
||||
* A process plugin can use any number of methods instead of (but not in
|
||||
* addition to) transform with the same arguments and then the plugin
|
||||
* configuration needs to provide the name of the method to be called via the
|
||||
* "method" key. See \Drupal\migrate\Plugin\migrate\process\SkipOnEmpty and
|
||||
* migrate.migration.d6_field_instance_widget_settings.yml for examples.
|
||||
*
|
||||
* @see \Drupal\migrate\Plugin\MigratePluginManager
|
||||
* @see \Drupal\migrate\ProcessPluginBase
|
||||
* @see \Drupal\migrate\Annotation\MigrateProcessPlugin
|
||||
* @see plugin_api
|
||||
*
|
||||
* @ingroup migration
|
||||
*/
|
||||
interface MigrateProcessInterface extends PluginInspectionInterface {
|
||||
|
||||
/**
|
||||
* Performs the associated process.
|
||||
*
|
||||
* @param mixed $value
|
||||
* The value to be transformed.
|
||||
* @param \Drupal\migrate\MigrateExecutableInterface $migrate_executable
|
||||
* The migration in which this process is being executed.
|
||||
* @param \Drupal\migrate\Row $row
|
||||
* The row from the source to process. Normally, just transforming the
|
||||
* value is adequate but very rarely you might need to change two columns
|
||||
* at the same time or something like that.
|
||||
* @param string $destination_property
|
||||
* The destination property currently worked on. This is only used
|
||||
* together with the $row above.
|
||||
*
|
||||
* @return string|array
|
||||
* The newly transformed value.
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property);
|
||||
|
||||
/**
|
||||
* Indicates whether the returned value requires multiple handling.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE when the returned value contains a list of values to be processed.
|
||||
* For example, when the 'source' property is a string and the value found
|
||||
* is an array.
|
||||
*/
|
||||
public function multiple();
|
||||
|
||||
}
|
65
core/modules/migrate/src/Plugin/MigrateSourceInterface.php
Normal file
65
core/modules/migrate/src/Plugin/MigrateSourceInterface.php
Normal file
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\MigrateSourceInterface.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin;
|
||||
use Drupal\Component\Plugin\PluginInspectionInterface;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* Defines an interface for migrate sources.
|
||||
*
|
||||
* @see \Drupal\migrate\Plugin\MigratePluginManager
|
||||
* @see \Drupal\migrate\Annotation\MigrateSource
|
||||
* @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
|
||||
* @see plugin_api
|
||||
*
|
||||
* @ingroup migration
|
||||
*/
|
||||
interface MigrateSourceInterface extends \Countable, \Iterator, PluginInspectionInterface {
|
||||
|
||||
/**
|
||||
* Returns available fields on the source.
|
||||
*
|
||||
* @return array
|
||||
* Available fields in the source, keys are the field machine names as used
|
||||
* in field mappings, values are descriptions.
|
||||
*/
|
||||
public function fields();
|
||||
|
||||
/**
|
||||
* Returns the iterator that will yield the row arrays to be processed.
|
||||
*
|
||||
* @return \Iterator
|
||||
* The iterator object.
|
||||
*
|
||||
* @throws \Exception
|
||||
* Cannot obtain a valid iterator.
|
||||
*/
|
||||
public function getIterator();
|
||||
|
||||
/**
|
||||
* Add additional data to the row.
|
||||
*
|
||||
* @param \Drupal\Migrate\Row $row
|
||||
* The row object.
|
||||
*
|
||||
* @return bool
|
||||
* FALSE if this row needs to be skipped.
|
||||
*/
|
||||
public function prepareRow(Row $row);
|
||||
|
||||
public function __toString();
|
||||
|
||||
/**
|
||||
* Get the source ids.
|
||||
*
|
||||
* @return array
|
||||
* The source ids.
|
||||
*/
|
||||
public function getIds();
|
||||
|
||||
}
|
23
core/modules/migrate/src/Plugin/RequirementsInterface.php
Normal file
23
core/modules/migrate/src/Plugin/RequirementsInterface.php
Normal file
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\RequirementsInterface.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin;
|
||||
|
||||
/**
|
||||
* An interface to check for a migrate plugin requirements.
|
||||
*/
|
||||
interface RequirementsInterface {
|
||||
|
||||
/**
|
||||
* Checks if requirements for this plugin are OK.
|
||||
*
|
||||
* @throws \Drupal\migrate\Exception\RequirementsException
|
||||
* Thrown when requirements are not met.
|
||||
*/
|
||||
public function checkRequirements();
|
||||
|
||||
}
|
32
core/modules/migrate/src/Plugin/SourceEntityInterface.php
Normal file
32
core/modules/migrate/src/Plugin/SourceEntityInterface.php
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\SourceEntityInterface.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin;
|
||||
|
||||
/**
|
||||
* Interface for sources providing an entity.
|
||||
*/
|
||||
interface SourceEntityInterface {
|
||||
|
||||
/**
|
||||
* Whether this migration has a bundle migration.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE when the bundle_migration key is required.
|
||||
*/
|
||||
public function bundleMigrationRequired();
|
||||
|
||||
/**
|
||||
* The entity type id (user, node etc).
|
||||
*
|
||||
* This function is used when bundleMigrationRequired() is FALSE.
|
||||
*
|
||||
* @return string
|
||||
* The entity type id.
|
||||
*/
|
||||
public function entityTypeId();
|
||||
|
||||
}
|
35
core/modules/migrate/src/Plugin/migrate/destination/Book.php
Normal file
35
core/modules/migrate/src/Plugin/migrate/destination/Book.php
Normal file
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\migrate\destination\Book.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\destination;
|
||||
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* @MigrateDestination(
|
||||
* id = "book",
|
||||
* provider = "book"
|
||||
* )
|
||||
*/
|
||||
class Book extends EntityContentBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static function getEntityTypeId($plugin_id) {
|
||||
return 'node';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function updateEntity(EntityInterface $entity, Row $row) {
|
||||
$entity->book = $row->getDestinationProperty('book');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\migrate\destination\ComponentEntityDisplayBase.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\destination;
|
||||
|
||||
use Drupal\migrate\Entity\MigrationInterface;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
abstract class ComponentEntityDisplayBase extends DestinationBase {
|
||||
|
||||
const MODE_NAME = '';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function import(Row $row, array $old_destination_id_values = array()) {
|
||||
$values = array();
|
||||
// array_intersect_key() won't work because the order is important because
|
||||
// this is also the return value.
|
||||
foreach (array_keys($this->getIds()) as $id) {
|
||||
$values[$id] = $row->getDestinationProperty($id);
|
||||
}
|
||||
$entity = $this->getEntity($values['entity_type'], $values['bundle'], $values[static::MODE_NAME]);
|
||||
if (!$row->getDestinationProperty('hidden')) {
|
||||
$entity->setComponent($values['field_name'], $row->getDestinationProperty('options') ?: array());
|
||||
}
|
||||
else {
|
||||
$entity->removeComponent($values['field_name']);
|
||||
}
|
||||
$entity->save();
|
||||
return array_values($values);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIds() {
|
||||
$ids['entity_type']['type'] = 'string';
|
||||
$ids['bundle']['type'] = 'string';
|
||||
$ids[static::MODE_NAME]['type'] = 'string';
|
||||
$ids['field_name']['type'] = 'string';
|
||||
return $ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function fields(MigrationInterface $migration = NULL) {
|
||||
// This is intentionally left empty.
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the entity.
|
||||
*
|
||||
* @param string $entity_type
|
||||
* The entity type to retrieve.
|
||||
* @param string $bundle
|
||||
* The entity bundle.
|
||||
* @param string $mode
|
||||
* The display mode.
|
||||
*
|
||||
* @return \Drupal\Core\Entity\Display\EntityDisplayInterface
|
||||
* The entity display object.
|
||||
*/
|
||||
protected abstract function getEntity($entity_type, $bundle, $mode);
|
||||
|
||||
}
|
121
core/modules/migrate/src/Plugin/migrate/destination/Config.php
Normal file
121
core/modules/migrate/src/Plugin/migrate/destination/Config.php
Normal file
|
@ -0,0 +1,121 @@
|
|||
<?php
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\migrate\destination\Config.
|
||||
*
|
||||
* Provides Configuration Management destination plugin.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\destination;
|
||||
|
||||
use Drupal\Component\Plugin\DependentPluginInterface;
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\Entity\DependencyTrait;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\migrate\Entity\MigrationInterface;
|
||||
use Drupal\migrate\MigrateException;
|
||||
use Drupal\migrate\Row;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Drupal\Core\Config\Config as ConfigObject;
|
||||
|
||||
/**
|
||||
* Persist data to the config system.
|
||||
*
|
||||
* When a property is NULL, the default is used unless the configuration option
|
||||
* 'store null' is set to TRUE.
|
||||
*
|
||||
* @MigrateDestination(
|
||||
* id = "config"
|
||||
* )
|
||||
*/
|
||||
class Config extends DestinationBase implements ContainerFactoryPluginInterface, DependentPluginInterface {
|
||||
use DependencyTrait;
|
||||
|
||||
/**
|
||||
* The config object.
|
||||
*
|
||||
* @var \Drupal\Core\Config\Config
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* Constructs a Config destination object.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin ID for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\migrate\Entity\MigrationInterface $migration
|
||||
* The migration entity.
|
||||
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
|
||||
* The configuration factory.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, ConfigFactoryInterface $config_factory) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition, $migration);
|
||||
$this->config = $config_factory->getEditable($configuration['config_name']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration = NULL) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$migration,
|
||||
$container->get('config.factory')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function import(Row $row, array $old_destination_id_values = array()) {
|
||||
foreach ($row->getRawDestination() as $key => $value) {
|
||||
if (isset($value) || !empty($this->configuration['store null'])) {
|
||||
$this->config->set(str_replace(Row::PROPERTY_SEPARATOR, '.', $key), $value);
|
||||
}
|
||||
}
|
||||
$this->config->save();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw an exception because config can not be rolled back.
|
||||
*
|
||||
* @param array $destination_keys
|
||||
* The array of destination ids to roll back.
|
||||
*
|
||||
* @throws \Drupal\migrate\MigrateException
|
||||
*/
|
||||
public function rollbackMultiple(array $destination_keys) {
|
||||
throw new MigrateException('Configuration can not be rolled back');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function fields(MigrationInterface $migration = NULL) {
|
||||
// @todo Dynamically fetch fields using Config Schema API.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIds() {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function calculateDependencies() {
|
||||
$provider = explode('.', $this->config->getName(), 2)[0];
|
||||
$this->addDependency('module', $provider);
|
||||
return $this->dependencies;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\migrate\destination\DestinationBase.
|
||||
*/
|
||||
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\destination;
|
||||
|
||||
use Drupal\Core\Plugin\PluginBase;
|
||||
use Drupal\migrate\Entity\MigrationInterface;
|
||||
use Drupal\migrate\Exception\RequirementsException;
|
||||
use Drupal\migrate\Plugin\MigrateDestinationInterface;
|
||||
use Drupal\migrate\Plugin\RequirementsInterface;
|
||||
|
||||
/**
|
||||
* Base class for migrate destination classes.
|
||||
*
|
||||
* @see \Drupal\migrate\Plugin\MigrateDestinationInterface
|
||||
* @see \Drupal\migrate\Plugin\MigrateDestinationPluginManager
|
||||
* @see \Drupal\migrate\Annotation\MigrateDestination
|
||||
* @see plugin_api
|
||||
*
|
||||
* @ingroup migration
|
||||
*/
|
||||
abstract class DestinationBase extends PluginBase implements MigrateDestinationInterface, RequirementsInterface {
|
||||
|
||||
/**
|
||||
* The migration.
|
||||
*
|
||||
* @var \Drupal\migrate\Entity\MigrationInterface
|
||||
*/
|
||||
protected $migration;
|
||||
|
||||
/**
|
||||
* Constructs an entity destination plugin.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin_id for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param MigrationInterface $migration
|
||||
* The migration.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
$this->migration = $migration;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function checkRequirements() {
|
||||
if (empty($this->pluginDefinition['requirements_met'])) {
|
||||
throw new RequirementsException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify the Row before it is imported.
|
||||
*/
|
||||
public function preImport() {
|
||||
// By default we do nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify the Row before it is rolled back.
|
||||
*/
|
||||
public function preRollback() {
|
||||
// By default we do nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function postImport() {
|
||||
// By default we do nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function postRollback() {
|
||||
// By default we do nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function rollbackMultiple(array $destination_identifiers) {
|
||||
// By default we do nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCreated() {
|
||||
// TODO: Implement getCreated() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUpdated() {
|
||||
// TODO: Implement getUpdated() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function resetStats() {
|
||||
// TODO: Implement resetStats() method.
|
||||
}
|
||||
|
||||
}
|
182
core/modules/migrate/src/Plugin/migrate/destination/Entity.php
Normal file
182
core/modules/migrate/src/Plugin/migrate/destination/Entity.php
Normal file
|
@ -0,0 +1,182 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\migrate\destination\Entity.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\destination;
|
||||
|
||||
use Drupal\Component\Plugin\DependentPluginInterface;
|
||||
use Drupal\Core\Entity\DependencyTrait;
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\migrate\Entity\MigrationInterface;
|
||||
use Drupal\migrate\Row;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* @MigrateDestination(
|
||||
* id = "entity",
|
||||
* deriver = "Drupal\migrate\Plugin\Derivative\MigrateEntity"
|
||||
* )
|
||||
*/
|
||||
abstract class Entity extends DestinationBase implements ContainerFactoryPluginInterface, DependentPluginInterface {
|
||||
use DependencyTrait;
|
||||
|
||||
/**
|
||||
* The entity storage.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityStorageInterface
|
||||
*/
|
||||
protected $storage;
|
||||
|
||||
/**
|
||||
* The list of the bundles of this entity type.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $bundles;
|
||||
|
||||
/**
|
||||
* Construct a new entity.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin_id for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param MigrationInterface $migration
|
||||
* The migration.
|
||||
* @param EntityStorageInterface $storage
|
||||
* The storage for this entity type.
|
||||
* @param array $bundles
|
||||
* The list of bundles this entity type has.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, EntityStorageInterface $storage, array $bundles) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition, $migration);
|
||||
$this->storage = $storage;
|
||||
$this->bundles = $bundles;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration = NULL) {
|
||||
$entity_type_id = static::getEntityTypeId($plugin_id);
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$migration,
|
||||
$container->get('entity.manager')->getStorage($entity_type_id),
|
||||
array_keys($container->get('entity.manager')->getBundleInfo($entity_type_id))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the entity type from configuration or plugin id.
|
||||
*
|
||||
* @param string $plugin_id
|
||||
* The plugin id.
|
||||
*
|
||||
* @return string
|
||||
* The entity type.
|
||||
*/
|
||||
protected static function getEntityTypeId($plugin_id) {
|
||||
// Remove "entity:"
|
||||
return substr($plugin_id, 7);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function fields(MigrationInterface $migration = NULL) {
|
||||
// TODO: Implement fields() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates or loads an entity.
|
||||
*
|
||||
* @param \Drupal\migrate\Row $row
|
||||
* The row object.
|
||||
* @param array $old_destination_id_values
|
||||
* The old destination ids.
|
||||
*
|
||||
* @return \Drupal\Core\Entity\EntityInterface
|
||||
* The entity we're importing into.
|
||||
*/
|
||||
protected function getEntity(Row $row, array $old_destination_id_values) {
|
||||
$entity_id = $old_destination_id_values ? reset($old_destination_id_values) : $this->getEntityId($row);
|
||||
if (!empty($entity_id) && ($entity = $this->storage->load($entity_id))) {
|
||||
$this->updateEntity($entity, $row);
|
||||
}
|
||||
else {
|
||||
$values = $row->getDestination();
|
||||
// Stubs might not have the bundle specified.
|
||||
if ($row->isStub()) {
|
||||
$values = $this->processStubValues($values);
|
||||
}
|
||||
$entity = $this->storage->create($values);
|
||||
$entity->enforceIsNew();
|
||||
}
|
||||
return $entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the entity id of the row.
|
||||
*
|
||||
* @param \Drupal\migrate\Row $row
|
||||
* The row of data.
|
||||
* @return string
|
||||
* The entity id for the row we're importing.
|
||||
*/
|
||||
protected function getEntityId(Row $row) {
|
||||
return $row->getDestinationProperty($this->getKey('id'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the stub values.
|
||||
*
|
||||
* @param array $values
|
||||
* An array of destination values.
|
||||
*
|
||||
* @return array
|
||||
* The processed stub values.
|
||||
*/
|
||||
protected function processStubValues(array $values) {
|
||||
$values = array_intersect_key($values, $this->getIds());
|
||||
|
||||
$bundle_key = $this->getKey('bundle');
|
||||
if ($bundle_key && !isset($values[$bundle_key])) {
|
||||
$values[$bundle_key] = reset($this->bundles);
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a specific entity key.
|
||||
*
|
||||
* @param string $key
|
||||
* The name of the entity key to return.
|
||||
*
|
||||
* @return string|bool
|
||||
* The entity key, or FALSE if it does not exist.
|
||||
*
|
||||
* @see \Drupal\Core\Entity\EntityTypeInterface::getKeys()
|
||||
*/
|
||||
protected function getKey($key) {
|
||||
return $this->storage->getEntityType()->getKey($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function calculateDependencies() {
|
||||
$this->addDependency('module', $this->storage->getEntityType()->getProvider());
|
||||
return $this->dependencies;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\migrate\destination\EntityBaseFieldOverride.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\destination;
|
||||
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* @MigrateDestination(
|
||||
* id = "entity:base_field_override"
|
||||
* )
|
||||
*/
|
||||
class EntityBaseFieldOverride extends EntityConfigBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getEntityId(Row $row) {
|
||||
$entity_type = $row->getDestinationProperty('entity_type');
|
||||
$bundle = $row->getDestinationProperty('bundle');
|
||||
$field_name = $row->getDestinationProperty('field_name');
|
||||
return "$entity_type.$bundle.$field_name";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\migrate\destination\EntityComment.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\destination;
|
||||
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\Core\State\StateInterface;
|
||||
use Drupal\migrate\Entity\MigrationInterface;
|
||||
use Drupal\migrate\Plugin\MigratePluginManager;
|
||||
use Drupal\migrate\Row;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* @MigrateDestination(
|
||||
* id = "entity:comment"
|
||||
* )
|
||||
*/
|
||||
class EntityComment extends EntityContentBase {
|
||||
|
||||
/**
|
||||
* The state storage object.
|
||||
*
|
||||
* @var \Drupal\Core\State\StateInterface
|
||||
*/
|
||||
protected $state;
|
||||
|
||||
/**
|
||||
* Builds an comment entity destination.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin_id for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param MigrationInterface $migration
|
||||
* The migration.
|
||||
* @param EntityStorageInterface $storage
|
||||
* The storage for this entity type.
|
||||
* @param array $bundles
|
||||
* The list of bundles this entity type has.
|
||||
* @param \Drupal\migrate\Plugin\MigratePluginManager $plugin_manager
|
||||
* The migrate plugin manager.
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager service.
|
||||
* @param \Drupal\Core\State\StateInterface $state
|
||||
* The state storage object.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, EntityStorageInterface $storage, array $bundles, EntityManagerInterface $entity_manager, StateInterface $state) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition, $migration, $storage, $bundles, $entity_manager);
|
||||
$this->state = $state;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration = NULL) {
|
||||
$entity_type = static::getEntityTypeId($plugin_id);
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$migration,
|
||||
$container->get('entity.manager')->getStorage($entity_type),
|
||||
array_keys($container->get('entity.manager')->getBundleInfo($entity_type)),
|
||||
$container->get('entity.manager'),
|
||||
$container->get('state')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function import(Row $row, array $old_destination_id_values = array()) {
|
||||
if ($row->isStub() && ($state = $this->state->get('comment.maintain_entity_statistics', 0))) {
|
||||
$this->state->set('comment.maintain_entity_statistics', 0);
|
||||
}
|
||||
$return = parent::import($row, $old_destination_id_values);
|
||||
if ($row->isStub() && $state) {
|
||||
$this->state->set('comment.maintain_entity_statistics', $state);
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\migrate\destination\EntityCommentType.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\destination;
|
||||
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* @MigrateDestination(
|
||||
* id = "entity:comment_type"
|
||||
* )
|
||||
*/
|
||||
class EntityCommentType extends EntityConfigBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function import(Row $row, array $old_destination_id_values = array()) {
|
||||
$entity_ids = parent::import($row, $old_destination_id_values);
|
||||
\Drupal::service('comment.manager')->addBodyField(reset($entity_ids));
|
||||
return $entity_ids;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\migrate\destination\EntityConfigBase.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\destination;
|
||||
|
||||
use Drupal\Component\Utility\NestedArray;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\migrate\MigrateException;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* Class for importing configuration entities.
|
||||
*
|
||||
* This class serves as the import class for most configuration entities.
|
||||
* It can be necessary to provide a specific entity class if the configuration
|
||||
* entity has a compound id (see EntityFieldEntity) or it has specific setter
|
||||
* methods (see EntityDateFormat). When implementing an entity destination for
|
||||
* the latter case, make sure to add a test not only for importing but also
|
||||
* for re-importing (if that is supported).
|
||||
*/
|
||||
class EntityConfigBase extends Entity {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function import(Row $row, array $old_destination_id_values = array()) {
|
||||
if ($row->isStub()) {
|
||||
throw new MigrateException('Config entities can not be stubbed.');
|
||||
}
|
||||
$ids = $this->getIds();
|
||||
$id_key = $this->getKey('id');
|
||||
if (count($ids) > 1) {
|
||||
// Ids is keyed by the key name so grab the keys.
|
||||
$id_keys = array_keys($ids);
|
||||
if (!$row->getDestinationProperty($id_key)) {
|
||||
// Set the id into the destination in for form "val1.val2.val3".
|
||||
$row->setDestinationProperty($id_key, $this->generateId($row, $id_keys));
|
||||
}
|
||||
}
|
||||
$entity = $this->getEntity($row, $old_destination_id_values);
|
||||
$entity->save();
|
||||
if (count($ids) > 1) {
|
||||
// This can only be a config entity, content entities have their id key
|
||||
// and that's it.
|
||||
$return = array();
|
||||
foreach ($id_keys as $id_key) {
|
||||
$return[] = $entity->get($id_key);
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
return array($entity->id());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIds() {
|
||||
$id_key = $this->getKey('id');
|
||||
$ids[$id_key]['type'] = 'string';
|
||||
return $ids;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Updates an entity with the contents of a row.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityInterface $entity
|
||||
* The entity to update.
|
||||
* @param \Drupal\migrate\Row $row
|
||||
* The row object to update from.
|
||||
*/
|
||||
protected function updateEntity(EntityInterface $entity, Row $row) {
|
||||
foreach ($row->getRawDestination() as $property => $value) {
|
||||
$this->updateEntityProperty($entity, explode(Row::PROPERTY_SEPARATOR, $property), $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a (possible nested) entity property with a value.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityInterface $entity
|
||||
* The config entity.
|
||||
* @param array $parents
|
||||
* The array of parents.
|
||||
* @param string|object $value
|
||||
* The value to update to.
|
||||
*/
|
||||
protected function updateEntityProperty(EntityInterface $entity, array $parents, $value) {
|
||||
$top_key = array_shift($parents);
|
||||
$entity_value = $entity->get($top_key);
|
||||
if (is_array($entity_value)) {
|
||||
NestedArray::setValue($entity_value, $parents, $value);
|
||||
}
|
||||
else {
|
||||
$entity_value = $value;
|
||||
}
|
||||
$entity->set($top_key, $entity_value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an entity id.
|
||||
*
|
||||
* @param \Drupal\migrate\Row $row
|
||||
* The current row.
|
||||
* @param array $ids
|
||||
* The destination ids.
|
||||
*
|
||||
* @return string
|
||||
* The generated entity id.
|
||||
*/
|
||||
protected function generateId(Row $row, array $ids) {
|
||||
$id_values = array();
|
||||
foreach ($ids as $id) {
|
||||
$id_values[] = $row->getDestinationProperty($id);
|
||||
}
|
||||
return implode('.', $id_values);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\migrate\destination\EntityContentBase.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\destination;
|
||||
|
||||
use Drupal\Core\Entity\ContentEntityInterface;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\Core\TypedData\TypedDataInterface;
|
||||
use Drupal\migrate\Entity\MigrationInterface;
|
||||
use Drupal\migrate\Row;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* The destination class for all content entities lacking a specific class.
|
||||
*/
|
||||
class EntityContentBase extends Entity {
|
||||
|
||||
/**
|
||||
* Entity manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityManagerInterface
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* Constructs a content entity.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin ID for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\migrate\Entity\MigrationInterface $migration
|
||||
* The migration entity.
|
||||
* @param \Drupal\Core\Entity\EntityStorageInterface $storage
|
||||
* The storage for this entity type.
|
||||
* @param array $bundles
|
||||
* The list of bundles this entity type has.
|
||||
* @param \Drupal\migrate\Plugin\MigratePluginManager $plugin_manager
|
||||
* The plugin manager.
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager service.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, EntityStorageInterface $storage, array $bundles, EntityManagerInterface $entity_manager) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition, $migration, $storage, $bundles);
|
||||
$this->entityManager = $entity_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration = NULL) {
|
||||
$entity_type = static::getEntityTypeId($plugin_id);
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$migration,
|
||||
$container->get('entity.manager')->getStorage($entity_type),
|
||||
array_keys($container->get('entity.manager')->getBundleInfo($entity_type)),
|
||||
$container->get('entity.manager')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function import(Row $row, array $old_destination_id_values = array()) {
|
||||
$entity = $this->getEntity($row, $old_destination_id_values);
|
||||
return $this->save($entity, $old_destination_id_values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the entity.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\ContentEntityInterface $entity
|
||||
* The content entity.
|
||||
* @param array $old_destination_id_values
|
||||
* An array of destination id values.
|
||||
*
|
||||
* @return array
|
||||
* An array containing the entity id.
|
||||
*/
|
||||
protected function save(ContentEntityInterface $entity, array $old_destination_id_values = array()) {
|
||||
$entity->save();
|
||||
return array($entity->id());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIds() {
|
||||
$id_key = $this->getKey('id');
|
||||
$ids[$id_key]['type'] = 'integer';
|
||||
return $ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an entity with the new values from row.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityInterface $entity
|
||||
* The entity to update.
|
||||
* @param \Drupal\migrate\Row $row
|
||||
* The row object to update from.
|
||||
*/
|
||||
protected function updateEntity(EntityInterface $entity, Row $row) {
|
||||
foreach ($row->getDestination() as $field_name => $values) {
|
||||
$field = $entity->$field_name;
|
||||
if ($field instanceof TypedDataInterface) {
|
||||
$field->setValue($values);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\migrate\destination\EntityDateFormat.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\destination;
|
||||
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
|
||||
/**
|
||||
* @MigrateDestination(
|
||||
* id = "entity:date_format"
|
||||
* )
|
||||
*/
|
||||
class EntityDateFormat extends EntityConfigBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param \Drupal\Core\Datetime\DateFormatInterface $entity
|
||||
* The date entity.
|
||||
*/
|
||||
protected function updateEntityProperty(EntityInterface $entity, array $parents, $value) {
|
||||
if ($parents[0] == 'pattern') {
|
||||
$entity->setPattern($value);
|
||||
}
|
||||
else {
|
||||
parent::updateEntityProperty($entity, $parents, $value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\migrate\destination\EntityFieldInstance.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\destination;
|
||||
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* @MigrateDestination(
|
||||
* id = "entity:field_config"
|
||||
* )
|
||||
*/
|
||||
class EntityFieldInstance extends EntityConfigBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIds() {
|
||||
$ids['entity_type']['type'] = 'string';
|
||||
$ids['bundle']['type'] = 'string';
|
||||
$ids['field_name']['type'] = 'string';
|
||||
return $ids;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\migrate\destination\EntityFieldStorageConfig.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\destination;
|
||||
|
||||
/**
|
||||
* @MigrateDestination(
|
||||
* id = "entity:field_storage_config"
|
||||
* )
|
||||
*/
|
||||
class EntityFieldStorageConfig extends EntityConfigBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIds() {
|
||||
$ids['entity_type']['type'] = 'string';
|
||||
$ids['field_name']['type'] = 'string';
|
||||
return $ids;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,245 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\migrate\destination\EntityFile.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\destination;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\Core\File\FileSystemInterface;
|
||||
use Drupal\Core\StreamWrapper\LocalStream;
|
||||
use Drupal\Core\StreamWrapper\StreamWrapperManagerInterface;
|
||||
use Drupal\migrate\Entity\MigrationInterface;
|
||||
use Drupal\migrate\Row;
|
||||
use Drupal\migrate\MigrateException;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Every migration that uses this destination must have an optional
|
||||
* dependency on the d6_file migration to ensure it runs first.
|
||||
*
|
||||
* @MigrateDestination(
|
||||
* id = "entity:file"
|
||||
* )
|
||||
*/
|
||||
class EntityFile extends EntityContentBase {
|
||||
|
||||
/**
|
||||
* @var \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface
|
||||
*/
|
||||
protected $streamWrapperManager;
|
||||
|
||||
/**
|
||||
* @var \Drupal\Core\File\FileSystemInterface
|
||||
*/
|
||||
protected $fileSystem;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, EntityStorageInterface $storage, array $bundles, EntityManagerInterface $entity_manager, StreamWrapperManagerInterface $stream_wrappers, FileSystemInterface $file_system) {
|
||||
$configuration += array(
|
||||
'source_base_path' => '',
|
||||
'source_path_property' => 'filepath',
|
||||
'destination_path_property' => 'uri',
|
||||
'move' => FALSE,
|
||||
'urlencode' => FALSE,
|
||||
);
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition, $migration, $storage, $bundles, $entity_manager);
|
||||
|
||||
$this->streamWrapperManager = $stream_wrappers;
|
||||
$this->fileSystem = $file_system;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration = NULL) {
|
||||
$entity_type = static::getEntityTypeId($plugin_id);
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$migration,
|
||||
$container->get('entity.manager')->getStorage($entity_type),
|
||||
array_keys($container->get('entity.manager')->getBundleInfo($entity_type)),
|
||||
$container->get('entity.manager'),
|
||||
$container->get('stream_wrapper_manager'),
|
||||
$container->get('file_system')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function import(Row $row, array $old_destination_id_values = array()) {
|
||||
$file = $row->getSourceProperty($this->configuration['source_path_property']);
|
||||
$destination = $row->getDestinationProperty($this->configuration['destination_path_property']);
|
||||
$source = $this->configuration['source_base_path'] . $file;
|
||||
|
||||
// Ensure the source file exists, if it's a local URI or path.
|
||||
if ($this->isLocalUri($source) && !file_exists($source)) {
|
||||
throw new MigrateException(SafeMarkup::format('File @source does not exist.', ['@source' => $source]));
|
||||
}
|
||||
|
||||
// If the start and end file is exactly the same, there is nothing to do.
|
||||
if ($this->isLocationUnchanged($source, $destination)) {
|
||||
return parent::import($row, $old_destination_id_values);
|
||||
}
|
||||
|
||||
$replace = $this->getOverwriteMode($row);
|
||||
$success = $this->writeFile($source, $destination, $replace);
|
||||
if (!$success) {
|
||||
$dir = $this->getDirectory($destination);
|
||||
if (file_prepare_directory($dir, FILE_CREATE_DIRECTORY)) {
|
||||
$success = $this->writeFile($source, $destination, $replace);
|
||||
}
|
||||
else {
|
||||
throw new MigrateException(SafeMarkup::format('Could not create directory @dir', ['@dir' => $dir]));
|
||||
}
|
||||
}
|
||||
|
||||
if ($success) {
|
||||
return parent::import($row, $old_destination_id_values);
|
||||
}
|
||||
else {
|
||||
throw new MigrateException(SafeMarkup::format('File %source could not be copied to %destination.', ['%source' => $source, '%destination' => $destination]));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to move or copy a file.
|
||||
*
|
||||
* @param string $source
|
||||
* The source path or URI.
|
||||
* @param string $destination
|
||||
* The destination path or URI.
|
||||
* @param integer $replace
|
||||
* FILE_EXISTS_REPLACE (default) or FILE_EXISTS_RENAME.
|
||||
*
|
||||
* @return boolean
|
||||
* TRUE on success, FALSE on failure.
|
||||
*/
|
||||
protected function writeFile($source, $destination, $replace = FILE_EXISTS_REPLACE) {
|
||||
if ($this->configuration['move']) {
|
||||
return (boolean) file_unmanaged_move($source, $destination, $replace);
|
||||
}
|
||||
else {
|
||||
$destination = file_destination($destination, $replace);
|
||||
$source = $this->urlencode($source);
|
||||
return @copy($source, $destination);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines how to handle file conflicts.
|
||||
*
|
||||
* @param \Drupal\migrate\Row $row
|
||||
*
|
||||
* @return integer
|
||||
* Either FILE_EXISTS_REPLACE (default) or FILE_EXISTS_RENAME, depending
|
||||
* on the current configuration.
|
||||
*/
|
||||
protected function getOverwriteMode(Row $row) {
|
||||
if (!empty($this->configuration['rename'])) {
|
||||
$entity_id = $row->getDestinationProperty($this->getKey('id'));
|
||||
if ($entity_id && ($entity = $this->storage->load($entity_id))) {
|
||||
return FILE_EXISTS_RENAME;
|
||||
}
|
||||
}
|
||||
return FILE_EXISTS_REPLACE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the directory component of a URI or path.
|
||||
*
|
||||
* For URIs like public://foo.txt, the full physical path of public://
|
||||
* will be returned, since a scheme by itself will trip up certain file
|
||||
* API functions (such as file_prepare_directory()).
|
||||
*
|
||||
* @param string $uri
|
||||
* The URI or path.
|
||||
*
|
||||
* @return boolean|string
|
||||
* The directory component of the path or URI, or FALSE if it could not
|
||||
* be determined.
|
||||
*/
|
||||
protected function getDirectory($uri) {
|
||||
$dir = $this->fileSystem->dirname($uri);
|
||||
if (substr($dir, -3) == '://') {
|
||||
return $this->fileSystem->realpath($dir);
|
||||
}
|
||||
else {
|
||||
return $dir;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the source and destination URIs represent identical paths.
|
||||
* If either URI is a remote stream, will return FALSE.
|
||||
*
|
||||
* @param string $source
|
||||
* The source URI.
|
||||
* @param string $destination
|
||||
* The destination URI.
|
||||
*
|
||||
* @return boolean
|
||||
* TRUE if the source and destination URIs refer to the same physical path,
|
||||
* otherwise FALSE.
|
||||
*/
|
||||
protected function isLocationUnchanged($source, $destination) {
|
||||
if ($this->isLocalUri($source) && $this->isLocalUri($destination)) {
|
||||
return $this->fileSystem->realpath($source) === $this->fileSystem->realpath($destination);
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the given URI or path is considered local.
|
||||
*
|
||||
* A URI or path is considered local if it either has no scheme component,
|
||||
* or the scheme is implemented by a stream wrapper which extends
|
||||
* \Drupal\Core\StreamWrapper\LocalStream.
|
||||
*
|
||||
* @param string $uri
|
||||
* The URI or path to test.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
protected function isLocalUri($uri) {
|
||||
$scheme = $this->fileSystem->uriScheme($uri);
|
||||
return $scheme === FALSE || $this->streamWrapperManager->getViaScheme($scheme) instanceof LocalStream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Urlencode all the components of a remote filename.
|
||||
*
|
||||
* @param string $filename
|
||||
* The filename of the file to be urlencoded.
|
||||
*
|
||||
* @return string
|
||||
* The urlencoded filename.
|
||||
*/
|
||||
protected function urlencode($filename) {
|
||||
// Only apply to a full URL
|
||||
if ($this->configuration['urlencode'] && strpos($filename, '://')) {
|
||||
$components = explode('/', $filename);
|
||||
foreach ($components as $key => $component) {
|
||||
$components[$key] = rawurlencode($component);
|
||||
}
|
||||
$filename = implode('/', $components);
|
||||
// Actually, we don't want certain characters encoded
|
||||
$filename = str_replace('%3A', ':', $filename);
|
||||
$filename = str_replace('%3F', '?', $filename);
|
||||
$filename = str_replace('%26', '&', $filename);
|
||||
}
|
||||
return $filename;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\migrate\destination\EntityNodeType.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\destination;
|
||||
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* @MigrateDestination(
|
||||
* id = "entity:node_type"
|
||||
* )
|
||||
*/
|
||||
class EntityNodeType extends EntityConfigBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function import(Row $row, array $old_destination_id_values = array()) {
|
||||
$entity_ids = parent::import($row, $old_destination_id_values);
|
||||
if ($row->getDestinationProperty('create_body')) {
|
||||
$node_type = $this->storage->load(reset($entity_ids));
|
||||
node_add_body_field($node_type, $row->getDestinationProperty('create_body_label'));
|
||||
}
|
||||
return $entity_ids;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\migrate\destination\EntityRevision.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\destination;
|
||||
|
||||
use Drupal\Core\Entity\ContentEntityInterface;
|
||||
use Drupal\migrate\MigrateException;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* @MigrateDestination(
|
||||
* id = "entity_revision",
|
||||
* deriver = "Drupal\migrate\Plugin\Derivative\MigrateEntityRevision"
|
||||
* )
|
||||
*/
|
||||
class EntityRevision extends EntityContentBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static function getEntityTypeId($plugin_id) {
|
||||
// Remove entity_revision:
|
||||
return substr($plugin_id, 16);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the entity.
|
||||
*
|
||||
* @param \Drupal\migrate\Row $row
|
||||
* The row object.
|
||||
*
|
||||
* @return \Drupal\Core\Entity\EntityInterface|false
|
||||
* The entity or false if it can not be created.
|
||||
*/
|
||||
protected function getEntity(Row $row, array $old_destination_id_values) {
|
||||
$revision_id = $old_destination_id_values ? reset($old_destination_id_values) : $row->getDestinationProperty($this->getKey('revision'));
|
||||
if (!empty($revision_id) && ($entity = $this->storage->loadRevision($revision_id))) {
|
||||
$entity->setNewRevision(FALSE);
|
||||
}
|
||||
else {
|
||||
$entity_id = $row->getDestinationProperty($this->getKey('id'));
|
||||
$entity = $this->storage->load($entity_id);
|
||||
$entity->enforceIsNew(FALSE);
|
||||
$entity->setNewRevision(TRUE);
|
||||
}
|
||||
$this->updateEntity($entity, $row);
|
||||
$entity->isDefaultRevision(FALSE);
|
||||
return $entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function save(ContentEntityInterface $entity, array $old_destination_id_values = array()) {
|
||||
$entity->save();
|
||||
return array($entity->getRevisionId());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIds() {
|
||||
if ($key = $this->getKey('revision')) {
|
||||
$ids[$key]['type'] = 'integer';
|
||||
return $ids;
|
||||
}
|
||||
throw new MigrateException('This entity type does not support revisions.');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\migrate\destination\EntitySearchPage.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\destination;
|
||||
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* @MigrateDestination(
|
||||
* id = "entity:search_page"
|
||||
* )
|
||||
*/
|
||||
class EntitySearchPage extends EntityConfigBase {
|
||||
|
||||
/**
|
||||
* Updates the entity with the contents of a row.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityInterface $entity
|
||||
* The search page entity.
|
||||
* @param \Drupal\migrate\Row $row
|
||||
* The row object to update from.
|
||||
*/
|
||||
protected function updateEntity(EntityInterface $entity, Row $row) {
|
||||
$entity->setPlugin($row->getDestinationProperty('plugin'));
|
||||
$entity->getPlugin()->setConfiguration($row->getDestinationProperty('configuration'));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\migrate\destination\EntityTaxonomyTerm.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\destination;
|
||||
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* @MigrateDestination(
|
||||
* id = "entity:taxonomy_term"
|
||||
* )
|
||||
*/
|
||||
class EntityTaxonomyTerm extends EntityContentBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getEntity(Row $row, array $old_destination_id_values) {
|
||||
if ($row->isStub()) {
|
||||
$row->setDestinationProperty('name', $this->t('Stub name for source tid:') . $row->getSourceProperty('tid'));
|
||||
}
|
||||
return parent::getEntity($row, $old_destination_id_values);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\migrate\destination\EntityUser.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\destination;
|
||||
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\Core\Password\PasswordInterface;
|
||||
use Drupal\migrate\Entity\MigrationInterface;
|
||||
use Drupal\migrate\MigrateException;
|
||||
use Drupal\migrate\MigratePassword;
|
||||
use Drupal\migrate\Plugin\MigratePluginManager;
|
||||
use Drupal\migrate\Row;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* @MigrateDestination(
|
||||
* id = "entity:user"
|
||||
* )
|
||||
*/
|
||||
class EntityUser extends EntityContentBase {
|
||||
|
||||
/**
|
||||
* The password service class.
|
||||
*
|
||||
* @var \Drupal\Core\Password\PasswordInterface
|
||||
*/
|
||||
protected $password;
|
||||
|
||||
/**
|
||||
* Builds an user entity destination.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin_id for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param MigrationInterface $migration
|
||||
* The migration.
|
||||
* @param EntityStorageInterface $storage
|
||||
* The storage for this entity type.
|
||||
* @param array $bundles
|
||||
* The list of bundles this entity type has.
|
||||
* @param \Drupal\migrate\Plugin\MigratePluginManager $plugin_manager
|
||||
* The migrate plugin manager.
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager service.
|
||||
* @param \Drupal\Core\Password\PasswordInterface $password
|
||||
* The password service.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, EntityStorageInterface $storage, array $bundles, EntityManagerInterface $entity_manager, PasswordInterface $password) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition, $migration, $storage, $bundles, $entity_manager);
|
||||
if (isset($configuration['md5_passwords'])) {
|
||||
$this->password = $password;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration = NULL) {
|
||||
$entity_type = static::getEntityTypeId($plugin_id);
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$migration,
|
||||
$container->get('entity.manager')->getStorage($entity_type),
|
||||
array_keys($container->get('entity.manager')->getBundleInfo($entity_type)),
|
||||
$container->get('entity.manager'),
|
||||
$container->get('password')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @throws \Drupal\migrate\MigrateException
|
||||
*/
|
||||
public function import(Row $row, array $old_destination_id_values = array()) {
|
||||
if ($this->password) {
|
||||
if ($this->password instanceof MigratePassword) {
|
||||
$this->password->enableMd5Prefixing();
|
||||
}
|
||||
else {
|
||||
throw new MigrateException('Password service has been altered by another module, aborting.');
|
||||
}
|
||||
}
|
||||
$ids = parent::import($row, $old_destination_id_values);
|
||||
if ($this->password) {
|
||||
$this->password->disableMd5Prefixing();
|
||||
}
|
||||
|
||||
return $ids;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\migrate\destination\EntityViewMode.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\destination;
|
||||
|
||||
/**
|
||||
* @MigrateDestination(
|
||||
* id = "entity:entity_view_mode"
|
||||
* )
|
||||
*/
|
||||
class EntityViewMode extends EntityConfigBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIds() {
|
||||
$ids['targetEntityType']['type'] = 'string';
|
||||
$ids['mode']['type'] = 'string';
|
||||
return $ids;
|
||||
}
|
||||
|
||||
}
|
41
core/modules/migrate/src/Plugin/migrate/destination/Null.php
Normal file
41
core/modules/migrate/src/Plugin/migrate/destination/Null.php
Normal file
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\migrate\destination\Null.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\destination;
|
||||
|
||||
use Drupal\migrate\Entity\MigrationInterface;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* @MigrateDestination(
|
||||
* id = "null",
|
||||
* requirements_met = false
|
||||
* )
|
||||
*/
|
||||
class Null extends DestinationBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIds() {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function fields(MigrationInterface $migration = NULL) {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function import(Row $row, array $old_destination_id_values = array()) {
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\migrate\destination\PerComponentEntityDisplay.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\destination;
|
||||
|
||||
/**
|
||||
* This class imports one component of an entity display.
|
||||
*
|
||||
* @MigrateDestination(
|
||||
* id = "component_entity_display"
|
||||
* )
|
||||
*/
|
||||
class PerComponentEntityDisplay extends ComponentEntityDisplayBase {
|
||||
|
||||
const MODE_NAME = 'view_mode';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getEntity($entity_type, $bundle, $view_mode) {
|
||||
return entity_get_display($entity_type, $bundle, $view_mode);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\migrate\destination\PerComponentEntityFormDisplay.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\destination;
|
||||
|
||||
/**
|
||||
* This class imports one component of an entity form display.
|
||||
*
|
||||
* @MigrateDestination(
|
||||
* id = "component_entity_form_display"
|
||||
* )
|
||||
*/
|
||||
class PerComponentEntityFormDisplay extends ComponentEntityDisplayBase {
|
||||
|
||||
const MODE_NAME = 'form_mode';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getEntity($entity_type, $bundle, $form_mode) {
|
||||
return entity_get_form_display($entity_type, $bundle, $form_mode);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\migrate\destination\UrlAlias.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\destination;
|
||||
|
||||
use Drupal\Core\Path\AliasStorage;
|
||||
use Drupal\migrate\Entity\MigrationInterface;
|
||||
use Drupal\migrate\Row;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
|
||||
/**
|
||||
* @MigrateDestination(
|
||||
* id = "url_alias"
|
||||
* )
|
||||
*/
|
||||
class UrlAlias extends DestinationBase implements ContainerFactoryPluginInterface {
|
||||
|
||||
/**
|
||||
* The alias storage service.
|
||||
*
|
||||
* @var \Drupal\Core\Path\AliasStorage $aliasStorage
|
||||
*/
|
||||
protected $aliasStorage;
|
||||
|
||||
/**
|
||||
* Constructs an entity destination plugin.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin_id for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param MigrationInterface $migration
|
||||
* The migration.
|
||||
* @param \Drupal\Core\Path\AliasStorage $alias_storage
|
||||
* The alias storage service.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, AliasStorage $alias_storage) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition, $migration);
|
||||
$this->aliasStorage = $alias_storage;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration = NULL) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$migration,
|
||||
$container->get('path.alias_storage')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function import(Row $row, array $old_destination_id_values = array()) {
|
||||
|
||||
$path = $this->aliasStorage->save(
|
||||
$row->getDestinationProperty('source'),
|
||||
$row->getDestinationProperty('alias'),
|
||||
$row->getDestinationProperty('langcode'),
|
||||
$old_destination_id_values ? $old_destination_id_values[0] : NULL
|
||||
);
|
||||
|
||||
return array($path['pid']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIds() {
|
||||
$ids['pid']['type'] = 'integer';
|
||||
return $ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function fields(MigrationInterface $migration = NULL) {
|
||||
return [
|
||||
'pid' => 'The path id',
|
||||
'source' => 'The source path.',
|
||||
'alias' => 'The url alias.',
|
||||
'langcode' => 'The language code for the url.',
|
||||
];
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\migrate\destination\UserData.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\destination;
|
||||
|
||||
use Drupal\migrate\Entity\MigrationInterface;
|
||||
use Drupal\user\UserData as UserDataStorage;
|
||||
use Drupal\migrate\Row;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
|
||||
/**
|
||||
* @MigrateDestination(
|
||||
* id = "user_data"
|
||||
* )
|
||||
*/
|
||||
class UserData extends DestinationBase implements ContainerFactoryPluginInterface {
|
||||
|
||||
/**
|
||||
* @var \Drupal\user\UserData
|
||||
*/
|
||||
protected $userData;
|
||||
|
||||
/**
|
||||
* Builds an user data entity destination.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin_id for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\migrate\Entity\MigrationInterface $migration
|
||||
* The migration.
|
||||
* @param \Drupal\user\UserData $user_data
|
||||
* The user data service.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, UserDataStorage $user_data) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition, $migration);
|
||||
$this->userData = $user_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration = NULL) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$migration,
|
||||
$container->get('user.data')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function import(Row $row, array $old_destination_id_values = array()) {
|
||||
$uid = $row->getDestinationProperty('uid');
|
||||
$module = $row->getDestinationProperty('module');
|
||||
$key = $row->getDestinationProperty('key');
|
||||
$this->userData->set($module, $uid, $key, $row->getDestinationProperty('settings'));
|
||||
|
||||
return [$uid, $module, $key];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIds() {
|
||||
$ids['uid']['type'] = 'integer';
|
||||
$ids['module']['type'] = 'string';
|
||||
$ids['key']['type'] = 'string';
|
||||
return $ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function fields(MigrationInterface $migration = NULL) {
|
||||
return [
|
||||
'uid' => 'The user id.',
|
||||
'module' => 'The module name responsible for the settings.',
|
||||
'key' => 'The setting key to save under.',
|
||||
'settings' => 'The settings to save.',
|
||||
];
|
||||
}
|
||||
|
||||
}
|
793
core/modules/migrate/src/Plugin/migrate/id_map/Sql.php
Normal file
793
core/modules/migrate/src/Plugin/migrate/id_map/Sql.php
Normal file
|
@ -0,0 +1,793 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\migrate\id_map\Sql.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\id_map;
|
||||
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Core\Database\Connection;
|
||||
use Drupal\Core\Field\BaseFieldDefinition;
|
||||
use Drupal\Core\Plugin\PluginBase;
|
||||
use Drupal\migrate\Entity\MigrationInterface;
|
||||
use Drupal\migrate\MigrateException;
|
||||
use Drupal\migrate\MigrateMessageInterface;
|
||||
use Drupal\migrate\Plugin\MigrateIdMapInterface;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* Defines the sql based ID map implementation.
|
||||
*
|
||||
* It creates one map and one message table per migration entity to store the
|
||||
* relevant information.
|
||||
*
|
||||
* @PluginID("sql")
|
||||
*/
|
||||
class Sql extends PluginBase implements MigrateIdMapInterface {
|
||||
|
||||
/**
|
||||
* The migration map table name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $mapTableName;
|
||||
|
||||
/**
|
||||
* The message table name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $messageTableName;
|
||||
|
||||
/**
|
||||
* The migrate message.
|
||||
*
|
||||
* @var \Drupal\migrate\MigrateMessageInterface
|
||||
*/
|
||||
protected $message;
|
||||
|
||||
/**
|
||||
* The database connection for the map/message tables on the destination.
|
||||
*
|
||||
* @var \Drupal\Core\Database\Connection
|
||||
*/
|
||||
protected $database;
|
||||
|
||||
/**
|
||||
* @var \Drupal\Core\Database\Query\SelectInterface
|
||||
*/
|
||||
protected $query;
|
||||
|
||||
/**
|
||||
* The migration being done.
|
||||
*
|
||||
* @var \Drupal\migrate\Entity\MigrationInterface
|
||||
*/
|
||||
protected $migration;
|
||||
|
||||
/**
|
||||
* The source ID fields.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $sourceIdFields;
|
||||
|
||||
/**
|
||||
* The destination ID fields.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $destinationIdFields;
|
||||
|
||||
/**
|
||||
* Whether the plugin is already initialized.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $initialized;
|
||||
|
||||
/**
|
||||
* The result.
|
||||
*
|
||||
* @var null
|
||||
*/
|
||||
protected $result = NULL;
|
||||
|
||||
/**
|
||||
* The source identifiers.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $sourceIds = array();
|
||||
|
||||
/**
|
||||
* The destination identifiers.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $destinationIds = array();
|
||||
|
||||
/**
|
||||
* The current row.
|
||||
*
|
||||
* @var null
|
||||
*/
|
||||
protected $currentRow = NULL;
|
||||
|
||||
/**
|
||||
* The current key.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $currentKey = array();
|
||||
|
||||
/**
|
||||
* Constructs an SQL object.
|
||||
*
|
||||
* Sets up the tables and builds the maps,
|
||||
*
|
||||
* @param array $configuration
|
||||
* The configuration.
|
||||
* @param string $plugin_id
|
||||
* The plugin ID for the migration process to do.
|
||||
* @param mixed $plugin_definition
|
||||
* The configuration for the plugin.
|
||||
* @param \Drupal\migrate\Entity\MigrationInterface $migration
|
||||
* The migration to do.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
|
||||
$this->migration = $migration;
|
||||
}
|
||||
|
||||
/**
|
||||
* The source ID fields.
|
||||
*
|
||||
* @return array
|
||||
* The source ID fields.
|
||||
*/
|
||||
protected function sourceIdFields() {
|
||||
if (!isset($this->sourceIdFields)) {
|
||||
// Build the source and destination identifier maps.
|
||||
$this->sourceIdFields = array();
|
||||
$count = 1;
|
||||
foreach ($this->migration->getSourcePlugin()->getIds() as $field => $schema) {
|
||||
$this->sourceIdFields[$field] = 'sourceid' . $count++;
|
||||
}
|
||||
}
|
||||
return $this->sourceIdFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* The destination ID fields.
|
||||
*
|
||||
* @return array
|
||||
* The destination ID fields.
|
||||
*/
|
||||
protected function destinationIdFields() {
|
||||
if (!isset($this->destinationIdFields)) {
|
||||
$this->destinationIdFields = array();
|
||||
$count = 1;
|
||||
foreach ($this->migration->getDestinationPlugin()->getIds() as $field => $schema) {
|
||||
$this->destinationIdFields[$field] = 'destid' . $count++;
|
||||
}
|
||||
}
|
||||
return $this->destinationIdFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of the database map table.
|
||||
*
|
||||
* @return string
|
||||
* The map table name.
|
||||
*/
|
||||
public function mapTableName() {
|
||||
$this->init();
|
||||
return $this->mapTableName;
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of the database message table.
|
||||
*
|
||||
* @return string
|
||||
* The message table name.
|
||||
*/
|
||||
public function messageTableName() {
|
||||
$this->init();
|
||||
return $this->messageTableName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fully qualified map table name.
|
||||
*
|
||||
* @return string
|
||||
* The fully qualified map table name.
|
||||
*/
|
||||
public function getQualifiedMapTableName() {
|
||||
return $this->getDatabase()->getFullQualifiedTableName($this->mapTableName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the database connection.
|
||||
*
|
||||
* @return \Drupal\Core\Database\Connection
|
||||
* The database connection object.
|
||||
*/
|
||||
public function getDatabase() {
|
||||
if (!isset($this->database)) {
|
||||
$this->database = \Drupal::database();
|
||||
}
|
||||
$this->init();
|
||||
return $this->database;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the plugin.
|
||||
*/
|
||||
protected function init() {
|
||||
if (!$this->initialized) {
|
||||
$this->initialized = TRUE;
|
||||
// Default generated table names, limited to 63 characters.
|
||||
$machine_name = str_replace(':', '__', $this->migration->id());
|
||||
$prefix_length = strlen($this->getDatabase()->tablePrefix());
|
||||
$this->mapTableName = 'migrate_map_' . Unicode::strtolower($machine_name);
|
||||
$this->mapTableName = Unicode::substr($this->mapTableName, 0, 63 - $prefix_length);
|
||||
$this->messageTableName = 'migrate_message_' . Unicode::strtolower($machine_name);
|
||||
$this->messageTableName = Unicode::substr($this->messageTableName, 0, 63 - $prefix_length);
|
||||
$this->ensureTables();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setMessage(MigrateMessageInterface $message) {
|
||||
$this->message = $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the map and message tables if they don't already exist.
|
||||
*/
|
||||
protected function ensureTables() {
|
||||
if (!$this->getDatabase()->schema()->tableExists($this->mapTableName)) {
|
||||
// Generate appropriate schema info for the map and message tables,
|
||||
// and map from the source field names to the map/msg field names.
|
||||
$count = 1;
|
||||
$source_id_schema = array();
|
||||
$pks = array();
|
||||
foreach ($this->migration->getSourcePlugin()->getIds() as $id_definition) {
|
||||
$mapkey = 'sourceid' . $count++;
|
||||
$source_id_schema[$mapkey] = $this->getFieldSchema($id_definition);
|
||||
|
||||
// With InnoDB, utf8mb4-based primary keys can't be over 191 characters.
|
||||
// Use ASCII-based primary keys instead.
|
||||
if (isset($source_id_schema[$mapkey]['type']) && $source_id_schema[$mapkey]['type'] == 'varchar') {
|
||||
$source_id_schema[$mapkey]['type'] = 'varchar_ascii';
|
||||
}
|
||||
$pks[] = $mapkey;
|
||||
}
|
||||
|
||||
$fields = $source_id_schema;
|
||||
|
||||
// Add destination identifiers to map table.
|
||||
// TODO: How do we discover the destination schema?
|
||||
$count = 1;
|
||||
foreach ($this->migration->getDestinationPlugin()->getIds() as $id_definition) {
|
||||
// Allow dest identifier fields to be NULL (for IGNORED/FAILED
|
||||
// cases).
|
||||
$mapkey = 'destid' . $count++;
|
||||
$fields[$mapkey] = $this->getFieldSchema($id_definition);
|
||||
$fields[$mapkey]['not null'] = FALSE;
|
||||
}
|
||||
$fields['source_row_status'] = array(
|
||||
'type' => 'int',
|
||||
'size' => 'tiny',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => MigrateIdMapInterface::STATUS_IMPORTED,
|
||||
'description' => 'Indicates current status of the source row',
|
||||
);
|
||||
$fields['rollback_action'] = array(
|
||||
'type' => 'int',
|
||||
'size' => 'tiny',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => MigrateIdMapInterface::ROLLBACK_DELETE,
|
||||
'description' => 'Flag indicating what to do for this item on rollback',
|
||||
);
|
||||
$fields['last_imported'] = array(
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'description' => 'UNIX timestamp of the last time this row was imported',
|
||||
);
|
||||
$fields['hash'] = array(
|
||||
'type' => 'varchar',
|
||||
'length' => '64',
|
||||
'not null' => FALSE,
|
||||
'description' => 'Hash of source row data, for detecting changes',
|
||||
);
|
||||
$schema = array(
|
||||
'description' => 'Mappings from source identifier value(s) to destination identifier value(s).',
|
||||
'fields' => $fields,
|
||||
);
|
||||
if ($pks) {
|
||||
$schema['primary key'] = $pks;
|
||||
}
|
||||
$this->getDatabase()->schema()->createTable($this->mapTableName, $schema);
|
||||
|
||||
// Now do the message table.
|
||||
if (!$this->getDatabase()->schema()->tableExists($this->messageTableName())) {
|
||||
$fields = array();
|
||||
$fields['msgid'] = array(
|
||||
'type' => 'serial',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
);
|
||||
$fields += $source_id_schema;
|
||||
|
||||
$fields['level'] = array(
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 1,
|
||||
);
|
||||
$fields['message'] = array(
|
||||
'type' => 'text',
|
||||
'size' => 'medium',
|
||||
'not null' => TRUE,
|
||||
);
|
||||
$schema = array(
|
||||
'description' => 'Messages generated during a migration process',
|
||||
'fields' => $fields,
|
||||
'primary key' => array('msgid'),
|
||||
);
|
||||
if ($pks) {
|
||||
$schema['indexes']['sourcekey'] = $pks;
|
||||
}
|
||||
$this->getDatabase()->schema()->createTable($this->messageTableName(), $schema);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Add any missing columns to the map table.
|
||||
if (!$this->getDatabase()->schema()->fieldExists($this->mapTableName,
|
||||
'rollback_action')) {
|
||||
$this->getDatabase()->schema()->addField($this->mapTableName,
|
||||
'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->getDatabase()->schema()->fieldExists($this->mapTableName, 'hash')) {
|
||||
$this->getDatabase()->schema()->addField($this->mapTableName, 'hash', array(
|
||||
'type' => 'varchar',
|
||||
'length' => '64',
|
||||
'not null' => FALSE,
|
||||
'description' => 'Hash of source row data, for detecting changes',
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create schema from an id definition.
|
||||
*
|
||||
* @param array $id_definition
|
||||
* A field schema definition. Can be SQL schema or a type data
|
||||
* based schema. In the latter case, the value of type needs to be
|
||||
* $typed_data_type.$column
|
||||
* @return array
|
||||
*/
|
||||
protected function getFieldSchema(array $id_definition) {
|
||||
$type_parts = explode('.', $id_definition['type']);
|
||||
if (count($type_parts) == 1) {
|
||||
$type_parts[] = 'value';
|
||||
}
|
||||
$schema = BaseFieldDefinition::create($type_parts[0])->getColumns();
|
||||
return $schema[$type_parts[1]];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getRowBySource(array $source_id_values) {
|
||||
$query = $this->getDatabase()->select($this->mapTableName(), 'map')
|
||||
->fields('map');
|
||||
foreach ($this->sourceIdFields() as $source_id) {
|
||||
$query = $query->condition("map.$source_id", array_shift($source_id_values), '=');
|
||||
}
|
||||
$result = $query->execute();
|
||||
return $result->fetchAssoc();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getRowByDestination(array $destination_id_values) {
|
||||
$query = $this->getDatabase()->select($this->mapTableName(), 'map')
|
||||
->fields('map');
|
||||
foreach ($this->destinationIdFields() as $destination_id) {
|
||||
$query = $query->condition("map.$destination_id", array_shift($destination_id_values), '=');
|
||||
}
|
||||
$result = $query->execute();
|
||||
return $result->fetchAssoc();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getRowsNeedingUpdate($count) {
|
||||
$rows = array();
|
||||
$result = $this->getDatabase()->select($this->mapTableName(), 'map')
|
||||
->fields('map')
|
||||
->condition('source_row_status', MigrateIdMapInterface::STATUS_NEEDS_UPDATE)
|
||||
->range(0, $count)
|
||||
->execute();
|
||||
foreach ($result as $row) {
|
||||
$rows[] = $row;
|
||||
}
|
||||
return $rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function lookupSourceID(array $destination_id) {
|
||||
$query = $this->getDatabase()->select($this->mapTableName(), 'map')
|
||||
->fields('map', $this->sourceIdFields());
|
||||
foreach ($this->destinationIdFields() as $key_name) {
|
||||
$query = $query->condition("map.$key_name", array_shift($destination_id), '=');
|
||||
}
|
||||
$result = $query->execute();
|
||||
$source_id = $result->fetchAssoc();
|
||||
return array_values($source_id ?: array());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function lookupDestinationId(array $source_id) {
|
||||
if (empty($source_id)) {
|
||||
return array();
|
||||
}
|
||||
$query = $this->getDatabase()->select($this->mapTableName(), 'map')
|
||||
->fields('map', $this->destinationIdFields());
|
||||
foreach ($this->sourceIdFields() as $key_name) {
|
||||
$query = $query->condition("map.$key_name", array_shift($source_id), '=');
|
||||
}
|
||||
$result = $query->execute();
|
||||
$destination_id = $result->fetchAssoc();
|
||||
return array_values($destination_id ?: array());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function saveIdMapping(Row $row, array $destination_id_values, $source_row_status = MigrateIdMapInterface::STATUS_IMPORTED, $rollback_action = MigrateIdMapInterface::ROLLBACK_DELETE) {
|
||||
// Construct the source key.
|
||||
$source_id_values = $row->getSourceIdValues();
|
||||
// Construct the source key and initialize to empty variable keys.
|
||||
$keys = array();
|
||||
foreach ($this->sourceIdFields() as $field_name => $key_name) {
|
||||
// A NULL key value will fail.
|
||||
if (!isset($source_id_values[$field_name])) {
|
||||
$this->message->display(t(
|
||||
'Could not save to map table due to NULL value for key field !field',
|
||||
array('!field' => $field_name)), 'error');
|
||||
return;
|
||||
}
|
||||
$keys[$key_name] = $source_id_values[$field_name];
|
||||
}
|
||||
|
||||
$fields = array(
|
||||
'source_row_status' => (int) $source_row_status,
|
||||
'rollback_action' => (int) $rollback_action,
|
||||
'hash' => $row->getHash(),
|
||||
);
|
||||
$count = 0;
|
||||
foreach ($destination_id_values as $dest_id) {
|
||||
$fields['destid' . ++$count] = $dest_id;
|
||||
}
|
||||
if ($count && $count != count($this->destinationIdFields())) {
|
||||
$this->message->display(t('Could not save to map table due to missing destination id values'), 'error');
|
||||
return;
|
||||
}
|
||||
if ($this->migration->get('trackLastImported')) {
|
||||
$fields['last_imported'] = time();
|
||||
}
|
||||
if ($keys) {
|
||||
$this->getDatabase()->merge($this->mapTableName())
|
||||
->key($keys)
|
||||
->fields($fields)
|
||||
->execute();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function saveMessage(array $source_id_values, $message, $level = MigrationInterface::MESSAGE_ERROR) {
|
||||
$count = 1;
|
||||
foreach ($source_id_values as $id_value) {
|
||||
$fields['sourceid' . $count++] = $id_value;
|
||||
// If any key value is not set, we can't save.
|
||||
if (!isset($id_value)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
$fields['level'] = $level;
|
||||
$fields['message'] = $message;
|
||||
$this->getDatabase()->insert($this->messageTableName())
|
||||
->fields($fields)
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function prepareUpdate() {
|
||||
$this->getDatabase()->update($this->mapTableName())
|
||||
->fields(array('source_row_status' => MigrateIdMapInterface::STATUS_NEEDS_UPDATE))
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function processedCount() {
|
||||
return $this->getDatabase()->select($this->mapTableName())
|
||||
->countQuery()
|
||||
->execute()
|
||||
->fetchField();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function importedCount() {
|
||||
return $this->getDatabase()->select($this->mapTableName())
|
||||
->condition('source_row_status', array(MigrateIdMapInterface::STATUS_IMPORTED, MigrateIdMapInterface::STATUS_NEEDS_UPDATE), 'IN')
|
||||
->countQuery()
|
||||
->execute()
|
||||
->fetchField();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function updateCount() {
|
||||
return $this->countHelper(MigrateIdMapInterface::STATUS_NEEDS_UPDATE);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function errorCount() {
|
||||
return $this->countHelper(MigrateIdMapInterface::STATUS_FAILED);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function messageCount() {
|
||||
return $this->countHelper(NULL, $this->messageTableName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts records in a table.
|
||||
*
|
||||
* @param $status
|
||||
* An integer for the source_row_status column.
|
||||
* @param $table
|
||||
* The table to work
|
||||
* @return int
|
||||
* The number of records.
|
||||
*/
|
||||
protected function countHelper($status, $table = NULL) {
|
||||
$query = $this->getDatabase()->select($table ?: $this->mapTableName());
|
||||
if (isset($status)) {
|
||||
$query->condition('source_row_status', $status);
|
||||
}
|
||||
return $query->countQuery()->execute()->fetchField();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function delete(array $source_id_values, $messages_only = FALSE) {
|
||||
if (empty($source_id_values)) {
|
||||
throw new MigrateException('Without source identifier values it is impossible to find the row to delete.');
|
||||
}
|
||||
if (!$messages_only) {
|
||||
$map_query = $this->getDatabase()->delete($this->mapTableName());
|
||||
}
|
||||
$message_query = $this->getDatabase()->delete($this->messageTableName());
|
||||
$count = 1;
|
||||
foreach ($source_id_values as $id_value) {
|
||||
if (!$messages_only) {
|
||||
$map_query->condition('sourceid' . $count, $id_value);
|
||||
}
|
||||
$message_query->condition('sourceid' . $count, $id_value);
|
||||
$count++;
|
||||
}
|
||||
|
||||
if (!$messages_only) {
|
||||
$map_query->execute();
|
||||
}
|
||||
$message_query->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function deleteDestination(array $destination_id) {
|
||||
$map_query = $this->getDatabase()->delete($this->mapTableName());
|
||||
$message_query = $this->getDatabase()->delete($this->messageTableName());
|
||||
$source_id = $this->lookupSourceID($destination_id);
|
||||
if (!empty($source_id)) {
|
||||
$count = 1;
|
||||
foreach ($destination_id as $key_value) {
|
||||
$map_query->condition('destid' . $count, $key_value);
|
||||
$count++;
|
||||
}
|
||||
$map_query->execute();
|
||||
$count = 1;
|
||||
foreach ($source_id as $key_value) {
|
||||
$message_query->condition('sourceid' . $count, $key_value);
|
||||
$count++;
|
||||
}
|
||||
$message_query->execute();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setUpdate(array $source_id) {
|
||||
if (empty($source_id)) {
|
||||
throw new MigrateException('No source identifiers provided to update.');
|
||||
}
|
||||
$query = $this->getDatabase()
|
||||
->update($this->mapTableName())
|
||||
->fields(array('source_row_status' => MigrateIdMapInterface::STATUS_NEEDS_UPDATE));
|
||||
$count = 1;
|
||||
foreach ($source_id as $key_value) {
|
||||
$query->condition('sourceid' . $count++, $key_value);
|
||||
}
|
||||
$query->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function deleteBulk(array $source_id_values) {
|
||||
// If we have a single-column key, we can shortcut it.
|
||||
if (count($this->migration->getSourcePlugin()->getIds()) == 1) {
|
||||
$sourceids = array();
|
||||
foreach ($source_id_values as $source_id) {
|
||||
$sourceids[] = $source_id;
|
||||
}
|
||||
$this->getDatabase()->delete($this->mapTableName())
|
||||
->condition('sourceid1', $sourceids, 'IN')
|
||||
->execute();
|
||||
$this->getDatabase()->delete($this->messageTableName())
|
||||
->condition('sourceid1', $sourceids, 'IN')
|
||||
->execute();
|
||||
}
|
||||
else {
|
||||
foreach ($source_id_values as $source_id) {
|
||||
$map_query = $this->getDatabase()->delete($this->mapTableName());
|
||||
$message_query = $this->getDatabase()->delete($this->messageTableName());
|
||||
$count = 1;
|
||||
foreach ($source_id as $key_value) {
|
||||
$map_query->condition('sourceid' . $count, $key_value);
|
||||
$message_query->condition('sourceid' . $count++, $key_value);
|
||||
}
|
||||
$map_query->execute();
|
||||
$message_query->execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function clearMessages() {
|
||||
$this->getDatabase()->truncate($this->messageTableName())->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function destroy() {
|
||||
$this->getDatabase()->schema()->dropTable($this->mapTableName());
|
||||
$this->getDatabase()->schema()->dropTable($this->messageTableName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of Iterator::rewind().
|
||||
*
|
||||
* This is called before beginning a foreach loop.
|
||||
*
|
||||
* @todo Support idlist, itemlimit.
|
||||
*/
|
||||
public function rewind() {
|
||||
$this->currentRow = NULL;
|
||||
$fields = array();
|
||||
foreach ($this->sourceIdFields() as $field) {
|
||||
$fields[] = $field;
|
||||
}
|
||||
foreach ($this->destinationIdFields() as $field) {
|
||||
$fields[] = $field;
|
||||
}
|
||||
|
||||
// @todo Make this work.
|
||||
/*
|
||||
if (isset($this->options['itemlimit'])) {
|
||||
$query = $query->range(0, $this->options['itemlimit']);
|
||||
}
|
||||
*/
|
||||
$this->result = $this->getDatabase()->select($this->mapTableName(), 'map')
|
||||
->fields('map', $fields)
|
||||
->execute();
|
||||
$this->next();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of Iterator::current().
|
||||
*
|
||||
* This is called when entering a loop iteration, returning the current row.
|
||||
*/
|
||||
public function current() {
|
||||
return $this->currentRow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of Iterator::key().
|
||||
*
|
||||
* This is 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().
|
||||
*
|
||||
* This is called at the bottom of the loop implicitly, as well as explicitly
|
||||
* from rewind().
|
||||
*/
|
||||
public function next() {
|
||||
$this->currentRow = $this->result->fetchAssoc();
|
||||
$this->currentKey = array();
|
||||
if ($this->currentRow) {
|
||||
foreach ($this->sourceIdFields() as $map_field) {
|
||||
$this->currentKey[$map_field] = $this->currentRow[$map_field];
|
||||
// Leave only destination fields.
|
||||
unset($this->currentRow[$map_field]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of Iterator::valid().
|
||||
*
|
||||
* This is 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.
|
||||
return $this->currentRow !== FALSE;
|
||||
}
|
||||
|
||||
}
|
39
core/modules/migrate/src/Plugin/migrate/process/Callback.php
Normal file
39
core/modules/migrate/src/Plugin/migrate/process/Callback.php
Normal file
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\migrate\process\Callback.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\process;
|
||||
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\ProcessPluginBase;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* This plugin allows source value to be passed to a callback.
|
||||
*
|
||||
* The current value is passed to a callable that returns the processed value.
|
||||
* This plugin allows simple processing of the value, such as strtolower(). The
|
||||
* callable takes the value as the single mandatory argument. No additional
|
||||
* arguments can be passed to the callback as this would make the migration YAML
|
||||
* file too complex.
|
||||
*
|
||||
* @MigrateProcessPlugin(
|
||||
* id = "callback"
|
||||
* )
|
||||
*/
|
||||
class Callback extends ProcessPluginBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
|
||||
if (is_callable($this->configuration['callable'])) {
|
||||
$value = call_user_func($this->configuration['callable'], $value);
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
}
|
41
core/modules/migrate/src/Plugin/migrate/process/Concat.php
Normal file
41
core/modules/migrate/src/Plugin/migrate/process/Concat.php
Normal file
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\migrate\process\Concat.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\process;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\migrate\MigrateException;
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\ProcessPluginBase;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* Concatenates the strings in the current value.
|
||||
*
|
||||
* @MigrateProcessPlugin(
|
||||
* id = "concat",
|
||||
* handle_multiples = TRUE
|
||||
* )
|
||||
*/
|
||||
class Concat extends ProcessPluginBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* Concatenates the strings in the current value.
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
|
||||
if (is_array($value)) {
|
||||
$delimiter = isset($this->configuration['delimiter']) ? $this->configuration['delimiter'] : '';
|
||||
return implode($delimiter, $value);
|
||||
}
|
||||
else {
|
||||
throw new MigrateException(sprintf('%s is not an array', SafeMarkup::checkPlain(var_export($value, TRUE))));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\migrate\process\DedupeBase.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\process;
|
||||
|
||||
use Drupal\migrate\ProcessPluginBase;
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\Row;
|
||||
use Drupal\migrate\MigrateException;
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
|
||||
/**
|
||||
* This abstract base contains the dedupe logic.
|
||||
*
|
||||
* These plugins avoid duplication at the destination. For example, when
|
||||
* creating filter format names, the current value is checked against the
|
||||
* existing filter format names and if it exists, a numeric postfix is added
|
||||
* and incremented until a unique value is created.
|
||||
*/
|
||||
abstract class DedupeBase extends ProcessPluginBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
|
||||
$i = 1;
|
||||
$postfix = isset($this->configuration['postfix']) ? $this->configuration['postfix'] : '';
|
||||
$start = isset($this->configuration['start']) ? $this->configuration['start'] : 0;
|
||||
if (!is_int($start)) {
|
||||
throw new MigrateException('The start position configuration key should be an integer. Omit this key to capture from the beginning of the string.');
|
||||
}
|
||||
$length = isset($this->configuration['length']) ? $this->configuration['length'] : NULL;
|
||||
if (!is_null($length) && !is_int($length)) {
|
||||
throw new MigrateException('The character length configuration key should be an integer. Omit this key to capture the entire string.');
|
||||
}
|
||||
// Use optional start or length to return a portion of deduplicated value.
|
||||
$value = Unicode::substr($value, $start, $length);
|
||||
$new_value = $value;
|
||||
while ($this->exists($new_value)) {
|
||||
$new_value = $value . $postfix . $i++;
|
||||
}
|
||||
return $new_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a query checking the existence of some value.
|
||||
*
|
||||
* @param mixed $value
|
||||
* The value to check.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the value exists.
|
||||
*/
|
||||
abstract protected function exists($value);
|
||||
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\migrate\process\DedupeEntity.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\process;
|
||||
|
||||
use Drupal\Core\Entity\Query\QueryFactory;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\migrate\Entity\MigrationInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Ensures value is not duplicated against an entity field.
|
||||
*
|
||||
* @MigrateProcessPlugin(
|
||||
* id = "dedupe_entity"
|
||||
* )
|
||||
*/
|
||||
class DedupeEntity extends DedupeBase implements ContainerFactoryPluginInterface {
|
||||
|
||||
/**
|
||||
* @var \Drupal\Core\Entity\Query\QueryFactoryInterface
|
||||
*/
|
||||
protected $entityQueryFactory;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, QueryFactory $entity_query_factory) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
$this->entityQueryFactory = $entity_query_factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration = NULL) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$migration,
|
||||
$container->get('entity.query')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function exists($value) {
|
||||
// Plugins are cached so for every run we need a new query object.
|
||||
return $this
|
||||
->entityQueryFactory
|
||||
->get($this->configuration['entity_type'], 'AND')
|
||||
->condition($this->configuration['field'], $value)
|
||||
->count()
|
||||
->execute();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\migrate\process\DefaultValue.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\process;
|
||||
|
||||
use Drupal\migrate\ProcessPluginBase;
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
|
||||
/**
|
||||
* This plugin sets missing values on the destination.
|
||||
*
|
||||
* @MigrateProcessPlugin(
|
||||
* id = "default_value"
|
||||
* )
|
||||
*/
|
||||
class DefaultValue extends ProcessPluginBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
|
||||
if (!empty($this->configuration['strict'])) {
|
||||
return isset($value) ? $value : $this->configuration['default_value'];
|
||||
}
|
||||
return $value ?: $this->configuration['default_value'];
|
||||
}
|
||||
}
|
41
core/modules/migrate/src/Plugin/migrate/process/Extract.php
Normal file
41
core/modules/migrate/src/Plugin/migrate/process/Extract.php
Normal file
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\migrate\process\Extract.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\process;
|
||||
|
||||
use Drupal\Component\Utility\NestedArray;
|
||||
use Drupal\migrate\ProcessPluginBase;
|
||||
use Drupal\migrate\MigrateException;
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* This plugin extracts a value from an array.
|
||||
*
|
||||
* @see https://www.drupal.org/node/2152731
|
||||
*
|
||||
* @MigrateProcessPlugin(
|
||||
* id = "extract"
|
||||
* )
|
||||
*/
|
||||
class Extract extends ProcessPluginBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
|
||||
if (!is_array($value)) {
|
||||
throw new MigrateException('Input should be an array.');
|
||||
}
|
||||
$new_value = NestedArray::getValue($value, $this->configuration['index'], $key_exists);
|
||||
if (!$key_exists) {
|
||||
throw new MigrateException('Array index missing, extraction failed.');
|
||||
}
|
||||
return $new_value;
|
||||
}
|
||||
|
||||
}
|
37
core/modules/migrate/src/Plugin/migrate/process/Flatten.php
Normal file
37
core/modules/migrate/src/Plugin/migrate/process/Flatten.php
Normal file
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\migrate\process\Flatten.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\process;
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\ProcessPluginBase;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* This plugin flattens the current value.
|
||||
*
|
||||
* During some types of processing (e.g. user permission splitting), what was
|
||||
* once a single value gets transformed into multiple values. This plugin will
|
||||
* flatten them back down to single values again.
|
||||
*
|
||||
* @see https://www.drupal.org/node/2154215
|
||||
*
|
||||
* @MigrateProcessPlugin(
|
||||
* id = "flatten",
|
||||
* handle_multiples = TRUE
|
||||
* )
|
||||
*/
|
||||
class Flatten extends ProcessPluginBase {
|
||||
|
||||
/**
|
||||
* Flatten nested array values to single array values.
|
||||
*
|
||||
* For example, array(array(1, 2, array(3, 4))) becomes array(1, 2, 3, 4).
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
|
||||
return iterator_to_array(new \RecursiveIteratorIterator(new \RecursiveArrayIterator($value)), FALSE);
|
||||
}
|
||||
}
|
72
core/modules/migrate/src/Plugin/migrate/process/Get.php
Normal file
72
core/modules/migrate/src/Plugin/migrate/process/Get.php
Normal file
|
@ -0,0 +1,72 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\migrate\process\Get.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\process;
|
||||
|
||||
use Drupal\migrate\ProcessPluginBase;
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* This plugin copies from the source to the destination.
|
||||
*
|
||||
* @MigrateProcessPlugin(
|
||||
* id = "get"
|
||||
* )
|
||||
*/
|
||||
class Get extends ProcessPluginBase {
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $multiple;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $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);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (is_string($source)) {
|
||||
$this->multiple = is_array($return[0]);
|
||||
return $return[0];
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function multiple() {
|
||||
return $this->multiple;
|
||||
}
|
||||
}
|
68
core/modules/migrate/src/Plugin/migrate/process/Iterator.php
Normal file
68
core/modules/migrate/src/Plugin/migrate/process/Iterator.php
Normal file
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\migrate\process\Iterator.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\process;
|
||||
|
||||
use Drupal\migrate\ProcessPluginBase;
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* This plugin iterates and processes an array.
|
||||
*
|
||||
* @see https://www.drupal.org/node/2135345
|
||||
*
|
||||
* @MigrateProcessPlugin(
|
||||
* id = "iterator",
|
||||
* handle_multiples = TRUE
|
||||
* )
|
||||
*/
|
||||
class Iterator extends ProcessPluginBase {
|
||||
|
||||
/**
|
||||
* Runs a process pipeline on each destination property per list item.
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
|
||||
$return = array();
|
||||
foreach ($value as $key => $new_value) {
|
||||
$new_row = new Row($new_value, array());
|
||||
$migrate_executable->processRow($new_row, $this->configuration['process']);
|
||||
$destination = $new_row->getDestination();
|
||||
if (array_key_exists('key', $this->configuration)) {
|
||||
$key = $this->transformKey($key, $migrate_executable, $new_row);
|
||||
}
|
||||
$return[$key] = $destination;
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the process pipeline for the current key.
|
||||
*
|
||||
* @param string|int $key
|
||||
* The current key.
|
||||
* @param \Drupal\migrate\MigrateExecutableInterface $migrate_executable
|
||||
* The migrate executable helper class.
|
||||
* @param \Drupal\migrate\Row $row
|
||||
* The current row after processing.
|
||||
*
|
||||
* @return mixed
|
||||
* The transformed key.
|
||||
*/
|
||||
protected function transformKey($key, MigrateExecutableInterface $migrate_executable, Row $row) {
|
||||
$process = array('key' => $this->configuration['key']);
|
||||
$migrate_executable->processRow($row, $process, $key);
|
||||
return $row->getDestinationProperty('key');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function multiple() {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\migrate\process\MachineName.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\process;
|
||||
|
||||
use Drupal\Component\Transliteration\TransliterationInterface;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\migrate\ProcessPluginBase;
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\Row;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* This plugin creates a machine name.
|
||||
*
|
||||
* The current value gets transliterated, non-alphanumeric characters removed
|
||||
* and replaced by an underscore and multiple underscores are collapsed into
|
||||
* one.
|
||||
*
|
||||
* @MigrateProcessPlugin(
|
||||
* id = "machine_name"
|
||||
* )
|
||||
*/
|
||||
class MachineName extends ProcessPluginBase implements ContainerFactoryPluginInterface {
|
||||
|
||||
/**
|
||||
* @var \Drupal\Component\Transliteration\TransliterationInterface
|
||||
*/
|
||||
protected $transliteration;
|
||||
|
||||
/**
|
||||
* Constructs a MachineName plugin.
|
||||
*
|
||||
* @param array $configuration
|
||||
* The plugin configuration.
|
||||
* @param string $plugin_id
|
||||
* The plugin ID.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin definition.
|
||||
* @param \Drupal\Component\Transliteration\TransliterationInterface $transliteration
|
||||
* The transliteration service.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, TransliterationInterface $transliteration) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
$this->transliteration = $transliteration;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$container->get('transliteration')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
|
||||
$new_value = $this->transliteration->transliterate($value, LanguageInterface::LANGCODE_DEFAULT, '_');
|
||||
$new_value = strtolower($new_value);
|
||||
$new_value = preg_replace('/[^a-z0-9_]+/', '_', $new_value);
|
||||
return preg_replace('/_+/', '_', $new_value);
|
||||
}
|
||||
|
||||
}
|
165
core/modules/migrate/src/Plugin/migrate/process/Migration.php
Normal file
165
core/modules/migrate/src/Plugin/migrate/process/Migration.php
Normal file
|
@ -0,0 +1,165 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\migrate\process\Migration.
|
||||
*/
|
||||
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\process;
|
||||
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\migrate\MigrateSkipProcessException;
|
||||
use Drupal\migrate\MigrateSkipRowException;
|
||||
use Drupal\migrate\Plugin\MigratePluginManager;
|
||||
use Drupal\migrate\ProcessPluginBase;
|
||||
use Drupal\migrate\Entity\MigrationInterface;
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\Row;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Calculates the value of a property based on a previous migration.
|
||||
*
|
||||
* @MigrateProcessPlugin(
|
||||
* id = "migration"
|
||||
* )
|
||||
*/
|
||||
class Migration extends ProcessPluginBase implements ContainerFactoryPluginInterface {
|
||||
|
||||
/**
|
||||
* @var \Drupal\migrate\Plugin\MigratePluginManager
|
||||
*/
|
||||
protected $processPluginManager;
|
||||
|
||||
/**
|
||||
* @var \Drupal\Core\Entity\EntityStorageInterface
|
||||
*/
|
||||
protected $migrationStorage;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, EntityStorageInterface $storage, MigratePluginManager $process_plugin_manager) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
$this->migrationStorage = $storage;
|
||||
$this->migration = $migration;
|
||||
$this->processPluginManager = $process_plugin_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration = NULL) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$migration,
|
||||
$container->get('entity.manager')->getStorage('migration'),
|
||||
$container->get('plugin.manager.migrate.process')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
|
||||
$migration_ids = $this->configuration['migration'];
|
||||
if (!is_array($migration_ids)) {
|
||||
$migration_ids = array($migration_ids);
|
||||
}
|
||||
$scalar = FALSE;
|
||||
if (!is_array($value)) {
|
||||
$scalar = TRUE;
|
||||
$value = array($value);
|
||||
}
|
||||
$this->skipOnEmpty($value);
|
||||
$self = FALSE;
|
||||
/** @var \Drupal\migrate\Entity\MigrationInterface[] $migrations */
|
||||
$migrations = $this->migrationStorage->loadMultiple($migration_ids);
|
||||
$destination_ids = NULL;
|
||||
$source_id_values = array();
|
||||
foreach ($migrations as $migration_id => $migration) {
|
||||
if ($migration_id == $this->migration->id()) {
|
||||
$self = TRUE;
|
||||
}
|
||||
if (isset($this->configuration['source_ids'][$migration_id])) {
|
||||
$configuration = array('source' => $this->configuration['source_ids'][$migration_id]);
|
||||
$source_id_values[$migration_id] = $this->processPluginManager
|
||||
->createInstance('get', $configuration, $this->migration)
|
||||
->transform(NULL, $migrate_executable, $row, $destination_property);
|
||||
}
|
||||
else {
|
||||
$source_id_values[$migration_id] = $value;
|
||||
}
|
||||
// Break out of the loop as soon as a destination ID is found.
|
||||
if ($destination_ids = $migration->getIdMap()->lookupDestinationID($source_id_values[$migration_id])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$destination_ids && ($self || isset($this->configuration['stub_id']) || count($migrations) == 1)) {
|
||||
// If the lookup didn't succeed, figure out which migration will do the
|
||||
// stubbing.
|
||||
if ($self) {
|
||||
$migration = $this->migration;
|
||||
}
|
||||
elseif (isset($this->configuration['stub_id'])) {
|
||||
$migration = $migrations[$this->configuration['stub_id']];
|
||||
}
|
||||
else {
|
||||
$migration = reset($migrations);
|
||||
}
|
||||
$destination_plugin = $migration->getDestinationPlugin(TRUE);
|
||||
// Only keep the process necessary to produce the destination ID.
|
||||
$process = $migration->get('process');
|
||||
// We already have the source id values but need to key them for the Row
|
||||
// constructor.
|
||||
$source_ids = $migration->getSourcePlugin()->getIds();
|
||||
$values = array();
|
||||
foreach (array_keys($source_ids) as $index => $source_id) {
|
||||
$values[$source_id] = $source_id_values[$migration->id()][$index];
|
||||
}
|
||||
|
||||
$stub_row = new Row($values + $migration->get('source'), $source_ids, TRUE);
|
||||
|
||||
// Do a normal migration with the stub row.
|
||||
$migrate_executable->processRow($stub_row, $process);
|
||||
$destination_ids = array();
|
||||
try {
|
||||
$destination_ids = $destination_plugin->import($stub_row);
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
$migrate_executable->saveMessage($e->getMessage());
|
||||
}
|
||||
}
|
||||
if ($destination_ids) {
|
||||
if ($scalar) {
|
||||
if (count($destination_ids) == 1) {
|
||||
return reset($destination_ids);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return $destination_ids;
|
||||
}
|
||||
}
|
||||
throw new MigrateSkipRowException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Skip the migration process entirely if the value is FALSE.
|
||||
*
|
||||
* @param mixed $value
|
||||
* The incoming value to transform.
|
||||
*
|
||||
* @throws \Drupal\migrate\MigrateSkipProcessException
|
||||
*/
|
||||
protected function skipOnEmpty($value) {
|
||||
if (!array_filter($value)) {
|
||||
throw new MigrateSkipProcessException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
93
core/modules/migrate/src/Plugin/migrate/process/Route.php
Normal file
93
core/modules/migrate/src/Plugin/migrate/process/Route.php
Normal file
|
@ -0,0 +1,93 @@
|
|||
<?php
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\migrate\process\Route.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\process;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\migrate\Entity\MigrationInterface;
|
||||
use Drupal\Core\Path\PathValidatorInterface;
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\ProcessPluginBase;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* @MigrateProcessPlugin(
|
||||
* id = "route"
|
||||
* )
|
||||
*/
|
||||
class Route extends ProcessPluginBase implements ContainerFactoryPluginInterface {
|
||||
|
||||
/**
|
||||
* @var \Drupal\Core\Path\PathValidatorInterface
|
||||
*/
|
||||
protected $pathValidator;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, PathValidatorInterface $pathValidator) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
$this->migration = $migration;
|
||||
$this->pathValidator = $pathValidator;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration = NULL) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$migration,
|
||||
$container->get('path.validator')
|
||||
);
|
||||
}
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* Set the destination route information based on the source link_path.
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
|
||||
list($link_path, $options) = $value;
|
||||
$extracted = $this->pathValidator->getUrlIfValidWithoutAccessCheck($link_path);
|
||||
$route = array();
|
||||
|
||||
if ($extracted) {
|
||||
if ($extracted->isExternal()) {
|
||||
$route['route_name'] = null;
|
||||
$route['route_parameters'] = array();
|
||||
$route['options'] = $options;
|
||||
$route['url'] = $extracted->getUri();
|
||||
}
|
||||
else {
|
||||
$route['route_name'] = $extracted->getRouteName();
|
||||
$route['route_parameters'] = $extracted->getRouteParameters();
|
||||
$route['options'] = $extracted->getOptions();
|
||||
|
||||
if (isset($options['query'])) {
|
||||
// If the querystring is stored as a string (as in D6), convert it
|
||||
// into an array.
|
||||
if (is_string($options['query'])) {
|
||||
parse_str($options['query'], $old_query);
|
||||
}
|
||||
else {
|
||||
$old_query = $options['query'];
|
||||
}
|
||||
$options['query'] = $route['options']['query'] + $old_query;
|
||||
unset($route['options']['query']);
|
||||
}
|
||||
$route['options'] = $route['options'] + $options;
|
||||
$route['url'] = null;
|
||||
}
|
||||
}
|
||||
|
||||
return $route;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\migrate\process\SkipOnEmpty.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\process;
|
||||
|
||||
use Drupal\migrate\MigrateSkipProcessException;
|
||||
use Drupal\migrate\ProcessPluginBase;
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\Row;
|
||||
use Drupal\migrate\MigrateSkipRowException;
|
||||
|
||||
/**
|
||||
* If the source evaluates to empty, we skip processing or the whole row.
|
||||
*
|
||||
* @MigrateProcessPlugin(
|
||||
* id = "skip_on_empty"
|
||||
* )
|
||||
*/
|
||||
class SkipOnEmpty extends ProcessPluginBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function row($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
|
||||
if (!$value) {
|
||||
throw new MigrateSkipRowException();
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function process($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
|
||||
if (!$value) {
|
||||
throw new MigrateSkipProcessException();
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\migrate\process\SkipRowIfNotSet.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\process;
|
||||
|
||||
use Drupal\migrate\ProcessPluginBase;
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\Row;
|
||||
use Drupal\migrate\MigrateSkipRowException;
|
||||
|
||||
/**
|
||||
* If the source evaluates to empty, we skip the current row.
|
||||
*
|
||||
* @MigrateProcessPlugin(
|
||||
* id = "skip_row_if_not_set",
|
||||
* handle_multiples = TRUE
|
||||
* )
|
||||
*/
|
||||
class SkipRowIfNotSet extends ProcessPluginBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
|
||||
if (!isset($value[$this->configuration['index']])) {
|
||||
throw new MigrateSkipRowException();
|
||||
}
|
||||
return $value[$this->configuration['index']];
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\migrate\process\StaticMap.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\process;
|
||||
|
||||
use Drupal\Component\Utility\NestedArray;
|
||||
use Drupal\migrate\ProcessPluginBase;
|
||||
use Drupal\migrate\MigrateException;
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\Row;
|
||||
use Drupal\migrate\MigrateSkipRowException;
|
||||
|
||||
/**
|
||||
* This plugin changes the current value based on a static lookup map.
|
||||
*
|
||||
* @see https://www.drupal.org/node/2143521
|
||||
*
|
||||
* @MigrateProcessPlugin(
|
||||
* id = "static_map"
|
||||
* )
|
||||
*/
|
||||
class StaticMap extends ProcessPluginBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
|
||||
$new_value = $value;
|
||||
if (is_array($value)) {
|
||||
if (!$value) {
|
||||
throw new MigrateException('Can not lookup without a value.');
|
||||
}
|
||||
}
|
||||
else {
|
||||
$new_value = array($value);
|
||||
}
|
||||
$new_value = NestedArray::getValue($this->configuration['map'], $new_value, $key_exists);
|
||||
if (!$key_exists) {
|
||||
if (isset($this->configuration['default_value'])) {
|
||||
if (!empty($this->configuration['bypass'])) {
|
||||
throw new MigrateException('Setting both default_value and bypass is invalid.');
|
||||
}
|
||||
return $this->configuration['default_value'];
|
||||
}
|
||||
if (empty($this->configuration['bypass'])) {
|
||||
throw new MigrateSkipRowException();
|
||||
}
|
||||
else {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
return $new_value;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\migrate\source\EmptySource.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\source;
|
||||
|
||||
/**
|
||||
* Source returning an empty row.
|
||||
*
|
||||
* This is generally useful when needing to create a field using a migration..
|
||||
*
|
||||
* @MigrateSource(
|
||||
* id = "empty"
|
||||
* )
|
||||
*/
|
||||
class EmptySource extends SourcePluginBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function fields() {
|
||||
return array(
|
||||
'id' => t('ID'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function initializeIterator() {
|
||||
return new \ArrayIterator(array(array('id' => '')));
|
||||
}
|
||||
|
||||
public function __toString() {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIds() {
|
||||
$ids['id']['type'] = 'string';
|
||||
return $ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function count() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,458 @@
|
|||
<?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\MigrateException;
|
||||
use Drupal\migrate\Plugin\MigrateIdMapInterface;
|
||||
use Drupal\migrate\Plugin\MigrateSourceInterface;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* The base class for all source plugins.
|
||||
*
|
||||
* @see \Drupal\migrate\Plugin\MigratePluginManager
|
||||
* @see \Drupal\migrate\Annotation\MigrateSource
|
||||
* @see \Drupal\migrate\Plugin\MigrateSourceInterface
|
||||
* @see plugin_api
|
||||
*
|
||||
* @ingroup migration
|
||||
*/
|
||||
abstract class SourcePluginBase extends PluginBase implements MigrateSourceInterface {
|
||||
|
||||
/**
|
||||
* @var \Drupal\Core\Extension\ModuleHandlerInterface
|
||||
*/
|
||||
protected $moduleHandler;
|
||||
|
||||
/**
|
||||
* @var \Drupal\migrate\Entity\MigrationInterface
|
||||
*/
|
||||
protected $migration;
|
||||
|
||||
/**
|
||||
* The name and type of the highwater property in the source.
|
||||
*
|
||||
* @var array
|
||||
*
|
||||
* @see $originalHighwater
|
||||
*/
|
||||
protected $highWaterProperty;
|
||||
|
||||
/**
|
||||
* The current row from the query
|
||||
*
|
||||
* @var \Drupal\Migrate\Row
|
||||
*/
|
||||
protected $currentRow;
|
||||
|
||||
/**
|
||||
* The primary key of the current row
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $currentSourceIds;
|
||||
|
||||
/**
|
||||
* 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 high water mark at the beginning of the import operation.
|
||||
*
|
||||
* If the source has a property for tracking changes (like Drupal ha
|
||||
* node.changed) then this is the highest value of those imported so far.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $originalHighWater;
|
||||
|
||||
/**
|
||||
* List of source IDs to process.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $idList = array();
|
||||
|
||||
/**
|
||||
* Whether this instance should cache the source count.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $cacheCounts = FALSE;
|
||||
|
||||
/**
|
||||
* Key to use for caching counts.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $cacheKey;
|
||||
|
||||
/**
|
||||
* Whether this instance should not attempt to count the source.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
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 \Drupal\Core\Cache\CacheBackendInterface
|
||||
*/
|
||||
protected $cache;
|
||||
|
||||
/**
|
||||
* @var \Drupal\migrate\Plugin\MigrateIdMapInterface
|
||||
*/
|
||||
protected $idMap;
|
||||
|
||||
/**
|
||||
* @var \Iterator
|
||||
*/
|
||||
protected $iterator;
|
||||
|
||||
// @TODO, find out how to remove this.
|
||||
// @see https://www.drupal.org/node/2443617
|
||||
public $migrateExecutable;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
$this->migration = $migration;
|
||||
|
||||
// Set up some defaults based on the source configuration.
|
||||
$this->cacheCounts = !empty($configuration['cache_counts']);
|
||||
$this->skipCount = !empty($configuration['skip_count']);
|
||||
$this->cacheKey = !empty($configuration['cache_key']) ? !empty($configuration['cache_key']) : NULL;
|
||||
$this->trackChanges = !empty($configuration['track_changes']) ? $configuration['track_changes'] : FALSE;
|
||||
|
||||
// Pull out the current highwater mark if we have a highwater property.
|
||||
if ($this->highWaterProperty = $this->migration->get('highWaterProperty')) {
|
||||
$this->originalHighWater = $this->migration->getHighWater();
|
||||
}
|
||||
|
||||
if ($id_list = $this->migration->get('idlist')) {
|
||||
$this->idList = $id_list;
|
||||
}
|
||||
|
||||
// Don't allow the use of both highwater and track changes together.
|
||||
if ($this->highWaterProperty && $this->trackChanges) {
|
||||
throw new MigrateException('You should either use a highwater mark or track changes not both. They are both designed to solve the same problem');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the iterator with the source data.
|
||||
*
|
||||
* @return array
|
||||
* An array of the data for this source.
|
||||
*/
|
||||
protected abstract function initializeIterator();
|
||||
|
||||
/**
|
||||
* Get the module handler.
|
||||
*
|
||||
* @return \Drupal\Core\Extension\ModuleHandlerInterface
|
||||
* The module handler.
|
||||
*/
|
||||
protected function getModuleHandler() {
|
||||
if (!isset($this->moduleHandler)) {
|
||||
$this->moduleHandler = \Drupal::moduleHandler();
|
||||
}
|
||||
return $this->moduleHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function prepareRow(Row $row) {
|
||||
|
||||
$result = TRUE;
|
||||
$result_hook = $this->getModuleHandler()->invokeAll('migrate_prepare_row', array($row, $this, $this->migration));
|
||||
$result_named_hook = $this->getModuleHandler()->invokeAll('migrate_' . $this->migration->id() . '_prepare_row', array($row, $this, $this->migration));
|
||||
|
||||
// We're explicitly skipping this row - keep track in the map table.
|
||||
if (($result_hook && in_array(FALSE, $result_hook)) || ($result_named_hook && in_array(FALSE, $result_named_hook))) {
|
||||
// Make sure we replace any previous messages for this item with any
|
||||
// new ones.
|
||||
$id_map = $this->migration->getIdMap();
|
||||
$id_map->delete($this->currentSourceIds, TRUE);
|
||||
$this->migrateExecutable->saveQueuedMessages();
|
||||
$id_map->saveIdMapping($row, array(), MigrateIdMapInterface::STATUS_IGNORED, $this->migrateExecutable->rollbackAction);
|
||||
$this->numIgnored++;
|
||||
$this->currentRow = NULL;
|
||||
$this->currentSourceIds = NULL;
|
||||
$result = FALSE;
|
||||
}
|
||||
elseif ($this->trackChanges) {
|
||||
// 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).
|
||||
$row->rehash();
|
||||
}
|
||||
$this->numProcessed++;
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the iterator that will yield the row arrays to be processed.
|
||||
*
|
||||
* @return \Iterator
|
||||
*/
|
||||
public function getIterator() {
|
||||
if (!isset($this->iterator)) {
|
||||
$this->iterator = $this->initializeIterator();
|
||||
}
|
||||
return $this->iterator;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function current() {
|
||||
return $this->currentRow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the iterator key.
|
||||
*
|
||||
* 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->currentSourceIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the iterator is currently valid.
|
||||
*
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewind the iterator.
|
||||
*
|
||||
* 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->getIterator()->rewind();
|
||||
$this->next();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* The migration iterates over rows returned by the source plugin. This
|
||||
* method determines the next row which will be processed and imported into
|
||||
* the system.
|
||||
*
|
||||
* The method tracks the source and destination IDs using the ID map plugin.
|
||||
*
|
||||
* This also takes care about highwater support. Highwater allows to reimport
|
||||
* rows from a previous migration run, which got changed in the meantime.
|
||||
* This is done by specifying a highwater field, which is compared with the
|
||||
* last time, the migration got executed (originalHighWater).
|
||||
*/
|
||||
public function next() {
|
||||
$this->currentSourceIds = NULL;
|
||||
$this->currentRow = NULL;
|
||||
|
||||
// In order to find the next row we want to process, we ask the source
|
||||
// plugin for the next possible row.
|
||||
while (!isset($this->currentRow) && $this->getIterator()->valid()) {
|
||||
|
||||
$row_data = $this->getIterator()->current() + $this->configuration;
|
||||
$this->getIterator()->next();
|
||||
$row = new Row($row_data, $this->migration->getSourcePlugin()->getIds(), $this->migration->get('destinationIds'));
|
||||
|
||||
// Populate the source key for this row.
|
||||
$this->currentSourceIds = $row->getSourceIdValues();
|
||||
|
||||
// Pick up the existing map row, if any, unless getNextRow() did it.
|
||||
if (!$this->mapRowAdded && ($id_map = $this->idMap->getRowBySource($this->currentSourceIds))) {
|
||||
$row->setIdMap($id_map);
|
||||
}
|
||||
|
||||
// In case we have specified an ID list, but the ID given by the source is
|
||||
// not in there, we skip the row.
|
||||
$id_in_the_list = $this->idList && in_array(reset($this->currentSourceIds), $this->idList);
|
||||
if ($this->idList && !$id_in_the_list) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Preparing the row gives source plugins the chance to skip.
|
||||
if ($this->prepareRow($row) === FALSE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check whether the row needs processing.
|
||||
// 1. Explicitly specified IDs.
|
||||
// 2. This row has not been imported yet.
|
||||
// 3. Explicitly set to update.
|
||||
// 4. The row is newer than the current highwater mark.
|
||||
// 5. If no such property exists then try by checking the hash of the row.
|
||||
if ($id_in_the_list || !$row->getIdMap() || $row->needsUpdate() || $this->aboveHighwater($row) || $this->rowChanged($row) ) {
|
||||
$this->currentRow = $row->freezeSource();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the incoming data is newer than what we've previously imported.
|
||||
*
|
||||
* @param \Drupal\migrate\Row $row
|
||||
* The row we're importing.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the highwater value in the row is greater than our current value.
|
||||
*/
|
||||
protected function aboveHighwater(Row $row) {
|
||||
return $this->highWaterProperty && $row->getSourceProperty($this->highWaterProperty['name']) > $this->originalHighWater;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the incoming row has changed since our last import.
|
||||
*
|
||||
* @param \Drupal\migrate\Row $row
|
||||
* The row we're importing.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the row has changed otherwise FALSE.
|
||||
*/
|
||||
protected function rowChanged(Row $row) {
|
||||
return $this->trackChanges && $row->changed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for currentSourceIds data member.
|
||||
*/
|
||||
public function getCurrentIds() {
|
||||
return $this->currentSourceIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for numIgnored data member.
|
||||
*/
|
||||
public function getIgnored() {
|
||||
return $this->numIgnored;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for numProcessed data member.
|
||||
*/
|
||||
public function getProcessed() {
|
||||
return $this->numProcessed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset numIgnored back to 0.
|
||||
*/
|
||||
public function resetStats() {
|
||||
$this->numIgnored = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the source count.
|
||||
*
|
||||
* Return a count of available source records, from the cache if appropriate.
|
||||
* Returns -1 if the source is not countable.
|
||||
*
|
||||
* @param bool $refresh
|
||||
* Whether or not to refresh the count.
|
||||
*
|
||||
* @return int
|
||||
* The count.
|
||||
*/
|
||||
public function count($refresh = FALSE) {
|
||||
if ($this->skipCount) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!isset($this->cacheKey)) {
|
||||
$this->cacheKey = hash('sha256', $this->getPluginId());
|
||||
}
|
||||
|
||||
// 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 = $this->getIterator()->count();
|
||||
$this->getCache()->set($this->cacheKey, $count, 'cache');
|
||||
}
|
||||
else {
|
||||
// Caching is in play, first try to retrieve a cached count.
|
||||
$cache_object = $this->getCache()->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 = $this->getIterator()->count();
|
||||
$this->getCache()->set($this->cacheKey, $count, 'cache');
|
||||
}
|
||||
}
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cache object.
|
||||
*
|
||||
* @return \Drupal\Core\Cache\CacheBackendInterface
|
||||
* The cache object.
|
||||
*/
|
||||
protected function getCache() {
|
||||
if (!isset($this->cache)) {
|
||||
$this->cache = \Drupal::cache('migrate');
|
||||
}
|
||||
return $this->cache;
|
||||
}
|
||||
|
||||
}
|
235
core/modules/migrate/src/Plugin/migrate/source/SqlBase.php
Normal file
235
core/modules/migrate/src/Plugin/migrate/source/SqlBase.php
Normal file
|
@ -0,0 +1,235 @@
|
|||
<?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\migrate\id_map\Sql;
|
||||
use Drupal\migrate\Plugin\MigrateIdMapInterface;
|
||||
|
||||
/**
|
||||
* Sources whose data may be fetched via DBTNG.
|
||||
*
|
||||
* By default, an existing database connection with key 'migrate' and target
|
||||
* 'default' is used. These may be overridden with explicit 'key' and/or
|
||||
* 'target' configuration keys. In addition, if the configuration key 'database'
|
||||
* is present, it is used as a database connection information array to define
|
||||
* the connection.
|
||||
*/
|
||||
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}
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition, $migration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the query string when the object is used a string.
|
||||
*
|
||||
* @return string
|
||||
* The query string.
|
||||
*/
|
||||
public function __toString() {
|
||||
return (string) $this->query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the database connection object.
|
||||
*
|
||||
* @return \Drupal\Core\Database\Connection
|
||||
* The database connection.
|
||||
*/
|
||||
public function getDatabase() {
|
||||
if (!isset($this->database)) {
|
||||
if (isset($this->configuration['target'])) {
|
||||
$target = $this->configuration['target'];
|
||||
}
|
||||
else {
|
||||
$target = 'default';
|
||||
}
|
||||
if (isset($this->configuration['key'])) {
|
||||
$key = $this->configuration['key'];
|
||||
}
|
||||
else {
|
||||
$key = 'migrate';
|
||||
}
|
||||
if (isset($this->configuration['database'])) {
|
||||
Database::addConnectionInfo($key, $target, $this->configuration['database']);
|
||||
}
|
||||
$this->database = Database::getConnection($target, $key);
|
||||
}
|
||||
return $this->database;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for database select.
|
||||
*/
|
||||
protected function select($table, $alias = NULL, array $options = array()) {
|
||||
$options['fetch'] = \PDO::FETCH_ASSOC;
|
||||
return $this->getDatabase()->select($table, $alias, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper for adding tags and metadata to the query.
|
||||
*
|
||||
* @return \Drupal\Core\Database\Query\SelectInterface
|
||||
* The query with additional tags and metadata.
|
||||
*/
|
||||
protected function prepareQuery() {
|
||||
$this->query = clone $this->query();
|
||||
$this->query->addTag('migrate');
|
||||
$this->query->addTag('migrate_' . $this->migration->id());
|
||||
$this->query->addMetaData('migration', $this->migration);
|
||||
|
||||
return $this->query;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 initializeIterator() {
|
||||
$this->prepareQuery();
|
||||
$high_water_property = $this->migration->get('highWaterProperty');
|
||||
|
||||
// Get the key values, for potential use in joining to the map table, or
|
||||
// enforcing idlist.
|
||||
$keys = array();
|
||||
|
||||
// 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 high water fields are in play, we want to accept all rows
|
||||
// above the high water 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 high water).
|
||||
$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->getIds() 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()->getQualifiedMapTableName(), 'map', $map_join);
|
||||
$conditions->isNull($alias . '.sourceid1');
|
||||
$conditions->condition($alias . '.source_row_status', 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->getIds());
|
||||
for ($count = 1; $count <= $n; $count++) {
|
||||
$map_key = 'sourceid' . $count;
|
||||
$this->query->addField($alias, $map_key, "migrate_map_$map_key");
|
||||
}
|
||||
if ($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, 'source_row_status', 'migrate_map_source_row_status');
|
||||
}
|
||||
// 3. If we are using high water marks, also include rows above the mark.
|
||||
// But, include all rows if the high water mark is not set.
|
||||
if (isset($high_water_property['name']) && ($high_water = $this->migration->getHighWater()) !== '') {
|
||||
if (isset($high_water_property['alias'])) {
|
||||
$high_water = $high_water_property['alias'] . '.' . $high_water_property['name'];
|
||||
}
|
||||
else {
|
||||
$high_water = $high_water_property['name'];
|
||||
}
|
||||
$conditions->condition($high_water, $high_water, '>');
|
||||
$condition_added = TRUE;
|
||||
}
|
||||
if ($condition_added) {
|
||||
$this->query->condition($conditions);
|
||||
}
|
||||
}
|
||||
|
||||
return new \IteratorIterator($this->query->execute());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Drupal\Core\Database\Query\SelectInterface
|
||||
*/
|
||||
abstract public function query();
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function count() {
|
||||
return $this->query()->countQuery()->execute()->fetchField();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we can join against the map table.
|
||||
*
|
||||
* This function specifically catches issues when we're migrating with
|
||||
* unique sets of credentials for the source and destination database.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if we can join against the map table otherwise FALSE.
|
||||
*/
|
||||
protected function mapJoinable() {
|
||||
if (!$this->getIds()) {
|
||||
return FALSE;
|
||||
}
|
||||
$id_map = $this->migration->getIdMap();
|
||||
if (!$id_map instanceof Sql) {
|
||||
return FALSE;
|
||||
}
|
||||
$id_map_database_options = $id_map->getDatabase()->getConnectionOptions();
|
||||
$source_database_options = $this->getDatabase()->getConnectionOptions();
|
||||
foreach (array('username', 'password', 'host', 'port', 'namespace', 'driver') as $key) {
|
||||
if (isset($source_database_options[$key])) {
|
||||
if ($id_map_database_options[$key] != $source_database_options[$key]) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
}
|
Reference in a new issue