updated core from 8.4 to 8.5 : bug with login_destination
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\migrate\Audit;
|
||||
|
||||
use Drupal\migrate\Plugin\MigrationInterface;
|
||||
|
||||
/**
|
||||
* Defines an exception to throw if an error occurs during a migration audit.
|
||||
*/
|
||||
class AuditException extends \RuntimeException {
|
||||
|
||||
/**
|
||||
* AuditException constructor.
|
||||
*
|
||||
* @param \Drupal\migrate\Plugin\MigrationInterface $migration
|
||||
* The migration that caused the exception.
|
||||
* @param string $message
|
||||
* The reason the audit failed.
|
||||
* @param \Exception $previous
|
||||
* (optional) The previous exception.
|
||||
*/
|
||||
public function __construct(MigrationInterface $migration, $message, \Exception $previous = NULL) {
|
||||
$message = sprintf('Cannot audit migration %s: %s', $migration->id(), $message);
|
||||
parent::__construct($message, 0, $previous);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\migrate\Audit;
|
||||
|
||||
use Drupal\Component\Render\MarkupInterface;
|
||||
use Drupal\migrate\Plugin\MigrationInterface;
|
||||
|
||||
/**
|
||||
* Encapsulates the result of a migration audit.
|
||||
*/
|
||||
class AuditResult implements MarkupInterface, \Countable {
|
||||
|
||||
/**
|
||||
* The audited migration.
|
||||
*
|
||||
* @var \Drupal\migrate\Plugin\MigrationInterface
|
||||
*/
|
||||
protected $migration;
|
||||
|
||||
/**
|
||||
* The result of the audit (TRUE if passed, FALSE otherwise).
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $status;
|
||||
|
||||
/**
|
||||
* The reasons why the migration passed or failed the audit.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $reasons = [];
|
||||
|
||||
/**
|
||||
* AuditResult constructor.
|
||||
*
|
||||
* @param \Drupal\migrate\Plugin\MigrationInterface $migration
|
||||
* The audited migration.
|
||||
* @param bool $status
|
||||
* The result of the audit (TRUE if passed, FALSE otherwise).
|
||||
* @param string[] $reasons
|
||||
* (optional) The reasons why the migration passed or failed the audit.
|
||||
*/
|
||||
public function __construct(MigrationInterface $migration, $status, array $reasons = []) {
|
||||
if (!is_bool($status)) {
|
||||
throw new \InvalidArgumentException('Audit results must have a boolean status.');
|
||||
}
|
||||
$this->migration = $migration;
|
||||
$this->status = $status;
|
||||
array_walk($reasons, [$this, 'addReason']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the audited migration.
|
||||
*
|
||||
* @return \Drupal\migrate\Plugin\MigrationInterface
|
||||
* The audited migration.
|
||||
*/
|
||||
public function getMigration() {
|
||||
return $this->migration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the boolean result of the audit.
|
||||
*
|
||||
* @return bool
|
||||
* The result of the audit. TRUE if the migration passed the audit, FALSE
|
||||
* otherwise.
|
||||
*/
|
||||
public function passed() {
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a reason why the migration passed or failed the audit.
|
||||
*
|
||||
* @param string|object $reason
|
||||
* The reason to add. Can be a string or a string-castable object.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addReason($reason) {
|
||||
array_push($this->reasons, (string) $reason);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a passing audit result for a migration.
|
||||
*
|
||||
* @param \Drupal\migrate\Plugin\MigrationInterface $migration
|
||||
* The audited migration.
|
||||
* @param string[] $reasons
|
||||
* (optional) The reasons why the migration passed the audit.
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function pass(MigrationInterface $migration, array $reasons = []) {
|
||||
return new static($migration, TRUE, $reasons);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a failing audit result for a migration.
|
||||
*
|
||||
* @param \Drupal\migrate\Plugin\MigrationInterface $migration
|
||||
* The audited migration.
|
||||
* @param array $reasons
|
||||
* (optional) The reasons why the migration failed the audit.
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function fail(MigrationInterface $migration, array $reasons = []) {
|
||||
return new static($migration, FALSE, $reasons);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements \Countable::count() for Twig template compatibility.
|
||||
*
|
||||
* @return int
|
||||
*
|
||||
* @see \Drupal\Component\Render\MarkupInterface
|
||||
*/
|
||||
public function count() {
|
||||
return count($this->reasons);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the reasons the migration passed or failed, as a string.
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @see \Drupal\Component\Render\MarkupInterface
|
||||
*/
|
||||
public function __toString() {
|
||||
return implode("\n", $this->reasons);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the reasons the migration passed or failed, for JSON serialization.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function jsonSerialize() {
|
||||
return $this->reasons;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\migrate\Audit;
|
||||
|
||||
use Drupal\migrate\Plugin\MigrationInterface;
|
||||
|
||||
/**
|
||||
* Defines an interface for migration auditors.
|
||||
*
|
||||
* A migration auditor is a class which can examine a migration to determine if
|
||||
* it will cause conflicts with data already existing in the destination system.
|
||||
* What kind of auditing it does, and how it does it, is up to the implementing
|
||||
* class.
|
||||
*/
|
||||
interface AuditorInterface {
|
||||
|
||||
/**
|
||||
* Audits a migration.
|
||||
*
|
||||
* @param \Drupal\migrate\Plugin\MigrationInterface $migration
|
||||
* The migration to audit.
|
||||
*
|
||||
* @throws \Drupal\migrate\Audit\AuditException
|
||||
* If the audit fails.
|
||||
*
|
||||
* @return \Drupal\migrate\Audit\AuditResult
|
||||
* The result of the audit.
|
||||
*/
|
||||
public function audit(MigrationInterface $migration);
|
||||
|
||||
/**
|
||||
* Audits a set of migrations.
|
||||
*
|
||||
* @param \Drupal\migrate\Plugin\MigrationInterface[] $migrations
|
||||
* The migrations to audit.
|
||||
*
|
||||
* @return \Drupal\migrate\Audit\AuditResult[]
|
||||
* The audit results, keyed by migration ID.
|
||||
*/
|
||||
public function auditMultiple(array $migrations);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\migrate\Audit;
|
||||
|
||||
/**
|
||||
* Defines an interface for destination and ID maps which track a highest ID.
|
||||
*
|
||||
* When implemented by destination plugins, getHighestId() should return the
|
||||
* highest ID of the destination entity type that exists in the system. So, for
|
||||
* example, the entity:node plugin should return the highest node ID that
|
||||
* exists, regardless of whether it was created by a migration.
|
||||
*
|
||||
* When implemented by an ID map, getHighestId() should return the highest
|
||||
* migrated ID of the destination entity type.
|
||||
*/
|
||||
interface HighestIdInterface {
|
||||
|
||||
/**
|
||||
* Returns the highest ID tracked by the implementing plugin.
|
||||
*
|
||||
* @return int
|
||||
* The highest ID.
|
||||
*/
|
||||
public function getHighestId();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\migrate\Audit;
|
||||
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
use Drupal\migrate\Plugin\MigrationInterface;
|
||||
|
||||
/**
|
||||
* Audits migrations that create content entities in the destination system.
|
||||
*/
|
||||
class IdAuditor implements AuditorInterface {
|
||||
|
||||
use StringTranslationTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function audit(MigrationInterface $migration) {
|
||||
// If the migration does not opt into auditing, it passes.
|
||||
if (!$migration->isAuditable()) {
|
||||
return AuditResult::pass($migration);
|
||||
}
|
||||
|
||||
$interface = HighestIdInterface::class;
|
||||
|
||||
$destination = $migration->getDestinationPlugin();
|
||||
if (!$destination instanceof HighestIdInterface) {
|
||||
throw new AuditException($migration, "Destination does not implement $interface");
|
||||
}
|
||||
|
||||
$id_map = $migration->getIdMap();
|
||||
if (!$id_map instanceof HighestIdInterface) {
|
||||
throw new AuditException($migration, "ID map does not implement $interface");
|
||||
}
|
||||
|
||||
if ($destination->getHighestId() > $id_map->getHighestId()) {
|
||||
return AuditResult::fail($migration, [
|
||||
$this->t('The destination system contains data which was not created by a migration.'),
|
||||
]);
|
||||
}
|
||||
return AuditResult::pass($migration);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function auditMultiple(array $migrations) {
|
||||
$conflicts = [];
|
||||
|
||||
foreach ($migrations as $migration) {
|
||||
$migration_id = $migration->getPluginId();
|
||||
$conflicts[$migration_id] = $this->audit($migration);
|
||||
}
|
||||
ksort($conflicts);
|
||||
return $conflicts;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,7 +5,7 @@ namespace Drupal\migrate\Exception;
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Defines an
|
||||
* Defines an exception thrown when a migration does not meet the requirements.
|
||||
*
|
||||
* @see \Drupal\migrate\Plugin\RequirementsInterface
|
||||
*/
|
||||
|
||||
@@ -96,16 +96,16 @@ class MigrateExecutable implements MigrateExecutableInterface {
|
||||
* @param \Drupal\migrate\Plugin\MigrationInterface $migration
|
||||
* The migration to run.
|
||||
* @param \Drupal\migrate\MigrateMessageInterface $message
|
||||
* The migrate message service.
|
||||
* (optional) The migrate message service.
|
||||
* @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
|
||||
* The event dispatcher.
|
||||
* (optional) The event dispatcher.
|
||||
*
|
||||
* @throws \Drupal\migrate\MigrateException
|
||||
*/
|
||||
public function __construct(MigrationInterface $migration, MigrateMessageInterface $message, EventDispatcherInterface $event_dispatcher = NULL) {
|
||||
public function __construct(MigrationInterface $migration, MigrateMessageInterface $message = NULL, EventDispatcherInterface $event_dispatcher = NULL) {
|
||||
$this->migration = $migration;
|
||||
$this->message = $message;
|
||||
$this->migration->getIdMap()->setMessage($message);
|
||||
$this->message = $message ?: new MigrateMessage();
|
||||
$this->migration->getIdMap()->setMessage($this->message);
|
||||
$this->eventDispatcher = $event_dispatcher;
|
||||
// Record the memory limit in bytes
|
||||
$limit = trim(ini_get('memory_limit'));
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\migrate\Plugin\Exception;
|
||||
|
||||
use Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException;
|
||||
|
||||
/**
|
||||
* Defines a class for bad plugin definition exceptions.
|
||||
*/
|
||||
class BadPluginDefinitionException extends InvalidPluginDefinitionException {
|
||||
|
||||
/**
|
||||
* Constructs a BadPluginDefinitionException.
|
||||
*
|
||||
* For the remaining parameters see \Exception.
|
||||
*
|
||||
* @param string $plugin_id
|
||||
* The plugin ID of the mapper.
|
||||
* @param string $property
|
||||
* The name of the property that is missing from the plugin.
|
||||
*
|
||||
* @see \Exception
|
||||
*/
|
||||
public function __construct($plugin_id, $property, $code = 0, \Exception $previous = NULL) {
|
||||
$message = sprintf('The %s plugin must define the %s property.', $plugin_id, $property);
|
||||
parent::__construct($plugin_id, $message, $code, $previous);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -154,6 +154,17 @@ class Migration extends PluginBase implements MigrationInterface, RequirementsIn
|
||||
*/
|
||||
protected $migration_tags = [];
|
||||
|
||||
/**
|
||||
* Whether the migration is auditable.
|
||||
*
|
||||
* If set to TRUE, the migration's IDs will be audited. This means that, if
|
||||
* the highest destination ID is greater than the highest source ID, a warning
|
||||
* will be displayed that entities might be overwritten.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $audit = FALSE;
|
||||
|
||||
/**
|
||||
* These migrations, if run, must be executed before this migration.
|
||||
*
|
||||
@@ -677,4 +688,11 @@ class Migration extends PluginBase implements MigrationInterface, RequirementsIn
|
||||
return $this->migration_tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isAuditable() {
|
||||
return (bool) $this->audit;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,6 +25,9 @@ trait MigrationDeriverTrait {
|
||||
'destination' => [
|
||||
'plugin' => 'null',
|
||||
],
|
||||
'idMap' => [
|
||||
'plugin' => 'null',
|
||||
],
|
||||
];
|
||||
return \Drupal::service('plugin.manager.migration')->createStubMigration($definition)->getSourcePlugin();
|
||||
}
|
||||
|
||||
@@ -322,4 +322,11 @@ interface MigrationInterface extends PluginInspectionInterface, DerivativeInspec
|
||||
*/
|
||||
public function getMigrationTags();
|
||||
|
||||
/**
|
||||
* Indicates if the migration is auditable.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isAuditable();
|
||||
|
||||
}
|
||||
|
||||
@@ -60,11 +60,22 @@ class MigrationPluginManager extends DefaultPluginManager implements MigrationPl
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* Gets the plugin discovery.
|
||||
*
|
||||
* This method overrides DefaultPluginManager::getDiscovery() in order to
|
||||
* search for migration configurations in the MODULENAME/migrations and
|
||||
* MODULENAME/migration_templates directories. Throws a deprecation notice if
|
||||
* the MODULENAME/migration_templates directory exists.
|
||||
*/
|
||||
protected function getDiscovery() {
|
||||
if (!isset($this->discovery)) {
|
||||
$directories = array_map(function ($directory) {
|
||||
// Check for use of the @deprecated /migration_templates directory.
|
||||
// @todo Remove use of /migration_templates in Drupal 9.0.0.
|
||||
if (is_dir($directory . '/migration_templates')) {
|
||||
@trigger_error('Use of the /migration_templates directory to store migration configuration files is deprecated in Drupal 8.1.0 and will be removed before Drupal 9.0.0. See https://www.drupal.org/node/2920988.', E_USER_DEPRECATED);
|
||||
}
|
||||
// But still accept configurations found in /migration_templates.
|
||||
return [$directory . '/migration_templates', $directory . '/migrations'];
|
||||
}, $this->moduleHandler->getModuleDirectories());
|
||||
|
||||
@@ -116,13 +127,7 @@ class MigrationPluginManager extends DefaultPluginManager implements MigrationPl
|
||||
}
|
||||
|
||||
/**
|
||||
* Create migrations given a tag.
|
||||
*
|
||||
* @param string $tag
|
||||
* A migration tag we want to filter by.
|
||||
*
|
||||
* @return array|\Drupal\migrate\Plugin\MigrationInterface[]
|
||||
* An array of migration objects with the given tag.
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function createInstancesByTag($tag) {
|
||||
$migrations = array_filter($this->getDefinitions(), function ($migration) use ($tag) {
|
||||
|
||||
@@ -40,4 +40,15 @@ interface MigrationPluginManagerInterface extends PluginManagerInterface {
|
||||
*/
|
||||
public function createStubMigration(array $definition);
|
||||
|
||||
/**
|
||||
* Create migrations given a tag.
|
||||
*
|
||||
* @param string $tag
|
||||
* A migration tag we want to filter by.
|
||||
*
|
||||
* @return array|\Drupal\migrate\Plugin\MigrationInterface[]
|
||||
* An array of migration objects with the given tag.
|
||||
*/
|
||||
public function createInstancesByTag($tag);
|
||||
|
||||
}
|
||||
|
||||
@@ -6,7 +6,14 @@ use Drupal\migrate\Plugin\MigrationInterface;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* Defines the base abstract class for component entity display.
|
||||
* Provides a destination plugin for migrating entity display components.
|
||||
*
|
||||
* Display modes provide different presentations for viewing ('view modes') or
|
||||
* editing ('form modes') content. This destination plugin is an abstract base
|
||||
* class for migrating fields and other components into view and form modes.
|
||||
*
|
||||
* @see \Drupal\migrate\Plugin\migrate\destination\PerComponentEntityDisplay
|
||||
* @see \Drupal\migrate\Plugin\migrate\destination\PerComponentEntityFormDisplay
|
||||
*/
|
||||
abstract class ComponentEntityDisplayBase extends DestinationBase {
|
||||
|
||||
|
||||
@@ -12,7 +12,12 @@ use Drupal\migrate\Plugin\RequirementsInterface;
|
||||
/**
|
||||
* Base class for migrate destination classes.
|
||||
*
|
||||
* @see \Drupal\migrate\Plugin\MigrateDestinationInterface
|
||||
* Migrate destination plugins perfom the import operation of the migration.
|
||||
* Destination plugins extend this abstract base class. A destination plugin
|
||||
* must implement at least fields(), getIds() and import() methods. Destination
|
||||
* plugins can also support rollback operations. For more
|
||||
* information, refer to \Drupal\migrate\Plugin\MigrateDestinationInterface.
|
||||
*
|
||||
* @see \Drupal\migrate\Plugin\MigrateDestinationPluginManager
|
||||
* @see \Drupal\migrate\Annotation\MigrateDestination
|
||||
* @see plugin_api
|
||||
|
||||
@@ -11,7 +11,48 @@ use Drupal\migrate\Row;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides entity destination plugin.
|
||||
* Provides a generic destination to import entities.
|
||||
*
|
||||
* Available configuration keys:
|
||||
* - translations: (optional) Boolean, if TRUE, the destination will be
|
||||
* associated with the langcode provided by the source plugin. Defaults to
|
||||
* FALSE.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* @code
|
||||
* source:
|
||||
* plugin: d7_node
|
||||
* process:
|
||||
* nid: tnid
|
||||
* vid: vid
|
||||
* langcode: language
|
||||
* title: title
|
||||
* ...
|
||||
* revision_timestamp: timestamp
|
||||
* destination:
|
||||
* plugin: entity:node
|
||||
* @endcode
|
||||
*
|
||||
* This will save the processed, migrated row as a node.
|
||||
*
|
||||
* @code
|
||||
* source:
|
||||
* plugin: d7_node
|
||||
* process:
|
||||
* nid: tnid
|
||||
* vid: vid
|
||||
* langcode: language
|
||||
* title: title
|
||||
* ...
|
||||
* revision_timestamp: timestamp
|
||||
* destination:
|
||||
* plugin: entity:node
|
||||
* translations: true
|
||||
* @endcode
|
||||
*
|
||||
* This will save the processed, migrated row as a node with the relevant
|
||||
* langcode because the translations configuration is set to "true".
|
||||
*
|
||||
* @MigrateDestination(
|
||||
* id = "entity",
|
||||
@@ -53,6 +94,10 @@ abstract class Entity extends DestinationBase implements ContainerFactoryPluginI
|
||||
* The list of bundles this entity type has.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, EntityStorageInterface $storage, array $bundles) {
|
||||
$plugin_definition += [
|
||||
'label' => $storage->getEntityType()->getPluralLabel(),
|
||||
];
|
||||
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition, $migration);
|
||||
$this->storage = $storage;
|
||||
$this->bundles = $bundles;
|
||||
|
||||
@@ -5,7 +5,42 @@ namespace Drupal\migrate\Plugin\migrate\destination;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* Provides entity base field override plugin.
|
||||
* Provides entity base field override destination plugin.
|
||||
*
|
||||
* Base fields are non-configurable fields that always exist on a given entity
|
||||
* type, like the 'title', 'created' and 'sticky' fields of the 'node' entity
|
||||
* type. Some entity types can have bundles, for example the node content types.
|
||||
* The base fields exist on all bundles but the bundles can override the
|
||||
* definitions. For example, the label for node 'title' base field can be
|
||||
* different on different content types.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* The example below migrates the node 'sticky' settings for each content type.
|
||||
* @code
|
||||
* id: d6_node_setting_sticky
|
||||
* label: Node type 'sticky' setting
|
||||
* migration_tags:
|
||||
* - Drupal 6
|
||||
* source:
|
||||
* plugin: d6_node_type
|
||||
* constants:
|
||||
* entity_type: node
|
||||
* field_name: sticky
|
||||
* process:
|
||||
* entity_type: 'constants/entity_type'
|
||||
* bundle: type
|
||||
* field_name: 'constants/field_name'
|
||||
* label:
|
||||
* plugin: default_value
|
||||
* default_value: 'Sticky at the top of lists'
|
||||
* 'default_value/0/value': 'options/sticky'
|
||||
* destination:
|
||||
* plugin: entity:base_field_override
|
||||
* migration_dependencies:
|
||||
* required:
|
||||
* - d6_node_type
|
||||
* @endcode
|
||||
*
|
||||
* @MigrateDestination(
|
||||
* id = "entity:base_field_override"
|
||||
|
||||
@@ -9,6 +9,7 @@ use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\Core\Field\FieldTypePluginManagerInterface;
|
||||
use Drupal\Core\TypedData\TranslatableInterface;
|
||||
use Drupal\Core\TypedData\TypedDataInterface;
|
||||
use Drupal\migrate\Audit\HighestIdInterface;
|
||||
use Drupal\migrate\Plugin\MigrationInterface;
|
||||
use Drupal\migrate\MigrateException;
|
||||
use Drupal\migrate\Plugin\MigrateIdMapInterface;
|
||||
@@ -16,9 +17,68 @@ use Drupal\migrate\Row;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* The destination class for all content entities lacking a specific class.
|
||||
* Provides destination class for all content entities lacking a specific class.
|
||||
*
|
||||
* Available configuration keys:
|
||||
* - translations: (optional) Boolean, indicates if the entity is translatable,
|
||||
* defaults to FALSE.
|
||||
* - overwrite_properties: (optional) A list of properties that will be
|
||||
* overwritten if an entity with the same ID already exists. Any properties
|
||||
* that are not listed will not be overwritten.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* The example below will create a 'node' entity of content type 'article'.
|
||||
*
|
||||
* The language of the source will be used because the configuration
|
||||
* 'translations: true' was set. Without this configuration option the site's
|
||||
* default language would be used.
|
||||
*
|
||||
* The example content type has fields 'title', 'body' and 'field_example'.
|
||||
* The text format of the body field is defaulted to 'basic_html'. The example
|
||||
* uses the EmbeddedDataSource source plugin for the sake of simplicity.
|
||||
*
|
||||
* If the migration is executed again in an update mode, any updates done in the
|
||||
* destination Drupal site to the 'title' and 'body' fields would be overwritten
|
||||
* with the original source values. Updates done to 'field_example' would be
|
||||
* preserved because 'field_example' is not included in 'overwrite_properties'
|
||||
* configuration.
|
||||
* @code
|
||||
* id: custom_article_migration
|
||||
* label: Custom article migration
|
||||
* source:
|
||||
* plugin: embedded_data
|
||||
* data_rows:
|
||||
* -
|
||||
* id: 1
|
||||
* langcode: 'fi'
|
||||
* title: 'Sivun otsikko'
|
||||
* field_example: 'Huhuu'
|
||||
* content: '<p>Hoi maailma</p>'
|
||||
* ids:
|
||||
* id:
|
||||
* type: integer
|
||||
* process:
|
||||
* nid: id
|
||||
* langcode: langcode
|
||||
* title: title
|
||||
* field_example: field_example
|
||||
* 'body/0/value': content
|
||||
* 'body/0/format':
|
||||
* plugin: default_value
|
||||
* default_value: basic_html
|
||||
* destination:
|
||||
* plugin: entity:node
|
||||
* default_bundle: article
|
||||
* translations: true
|
||||
* overwrite_properties:
|
||||
* - title
|
||||
* - body
|
||||
* @endcode
|
||||
*
|
||||
* @see \Drupal\migrate\Plugin\migrate\destination\EntityRevision
|
||||
*/
|
||||
class EntityContentBase extends Entity {
|
||||
class EntityContentBase extends Entity implements HighestIdInterface {
|
||||
|
||||
/**
|
||||
* Entity manager.
|
||||
@@ -111,12 +171,9 @@ class EntityContentBase extends Entity {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether this destination is for translations.
|
||||
*
|
||||
* @return bool
|
||||
* Whether this destination is for translations.
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function isTranslationDestination() {
|
||||
public function isTranslationDestination() {
|
||||
return !empty($this->configuration['translations']);
|
||||
}
|
||||
|
||||
@@ -218,7 +275,7 @@ class EntityContentBase extends Entity {
|
||||
if ($field_definition->isRequired() && is_null($row->getDestinationProperty($field_name))) {
|
||||
// Use the configured default value for this specific field, if any.
|
||||
if ($default_value = $field_definition->getDefaultValueLiteral()) {
|
||||
$values[] = $default_value;
|
||||
$values = $default_value;
|
||||
}
|
||||
else {
|
||||
// Otherwise, ask the field type to generate a sample value.
|
||||
@@ -294,4 +351,16 @@ class EntityContentBase extends Entity {
|
||||
] + $field_definition->getSettings();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getHighestId() {
|
||||
$values = $this->storage->getQuery()
|
||||
->accessCheck(FALSE)
|
||||
->sort($this->getKey('id'), 'DESC')
|
||||
->range(0, 1)
|
||||
->execute();
|
||||
return (int) current($values);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,12 +3,107 @@
|
||||
namespace Drupal\migrate\Plugin\migrate\destination;
|
||||
|
||||
use Drupal\Core\Entity\ContentEntityInterface;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\Core\Field\FieldTypePluginManagerInterface;
|
||||
use Drupal\Core\StringTranslation\TranslatableMarkup;
|
||||
use Drupal\migrate\MigrateException;
|
||||
use Drupal\migrate\Plugin\MigrationInterface;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* Provides entity revision destination plugin.
|
||||
*
|
||||
* Refer to the parent class for configuration keys:
|
||||
* \Drupal\migrate\Plugin\migrate\destination\EntityContentBase
|
||||
*
|
||||
* Entity revisions can only be migrated after the entity to which the revisions
|
||||
* belong has been migrated. For example, revisions of a given content type can
|
||||
* be migrated only after the nodes of that content type have been migrated.
|
||||
*
|
||||
* In order to avoid revision ID conflicts, make sure that the entity migration
|
||||
* also includes the revision ID. If the entity migration did not include the
|
||||
* revision ID, the entity would get the next available revision ID (1 when
|
||||
* migrating to a clean database). Then, when revisions are migrated after the
|
||||
* entities, the revision IDs would almost certainly collide.
|
||||
*
|
||||
* The examples below contain simple node and node revision migrations. The
|
||||
* examples use the EmbeddedDataSource source plugin for the sake of
|
||||
* simplicity. The important part of both examples is the 'vid' property, which
|
||||
* is the revision ID for nodes.
|
||||
*
|
||||
* Example of 'article' node migration, which must be executed before the
|
||||
* 'article' revisions.
|
||||
* @code
|
||||
* id: custom_article_migration
|
||||
* label: 'Custom article migration'
|
||||
* source:
|
||||
* plugin: embedded_data
|
||||
* data_rows:
|
||||
* -
|
||||
* nid: 1
|
||||
* vid: 2
|
||||
* revision_timestamp: 1514661000
|
||||
* revision_log: 'Second revision'
|
||||
* title: 'Current title'
|
||||
* content: '<p>Current content</p>'
|
||||
* ids:
|
||||
* nid:
|
||||
* type: integer
|
||||
* process:
|
||||
* nid: nid
|
||||
* vid: vid
|
||||
* revision_timestamp: revision_timestamp
|
||||
* revision_log: revision_log
|
||||
* title: title
|
||||
* 'body/0/value': content
|
||||
* 'body/0/format':
|
||||
* plugin: default_value
|
||||
* default_value: basic_html
|
||||
* destination:
|
||||
* plugin: entity:node
|
||||
* default_bundle: article
|
||||
* @endcode
|
||||
*
|
||||
* Example of the corresponding node revision migration, which must be executed
|
||||
* after the above migration.
|
||||
* @code
|
||||
* id: custom_article_revision_migration
|
||||
* label: 'Custom article revision migration'
|
||||
* source:
|
||||
* plugin: embedded_data
|
||||
* data_rows:
|
||||
* -
|
||||
* nid: 1
|
||||
* vid: 1
|
||||
* revision_timestamp: 1514660000
|
||||
* revision_log: 'First revision'
|
||||
* title: 'Previous title'
|
||||
* content: '<p>Previous content</p>'
|
||||
* ids:
|
||||
* nid:
|
||||
* type: integer
|
||||
* process:
|
||||
* nid:
|
||||
* plugin: migration_lookup
|
||||
* migration: custom_article_migration
|
||||
* source: nid
|
||||
* vid: vid
|
||||
* revision_timestamp: revision_timestamp
|
||||
* revision_log: revision_log
|
||||
* title: title
|
||||
* 'body/0/value': content
|
||||
* 'body/0/format':
|
||||
* plugin: default_value
|
||||
* default_value: basic_html
|
||||
* destination:
|
||||
* plugin: entity_revision:node
|
||||
* default_bundle: article
|
||||
* migration_dependencies:
|
||||
* required:
|
||||
* - custom_article_migration
|
||||
* @endcode
|
||||
*
|
||||
* @MigrateDestination(
|
||||
* id = "entity_revision",
|
||||
* deriver = "Drupal\migrate\Plugin\Derivative\MigrateEntityRevision"
|
||||
@@ -16,6 +111,16 @@ use Drupal\migrate\Row;
|
||||
*/
|
||||
class EntityRevision extends EntityContentBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, EntityStorageInterface $storage, array $bundles, EntityManagerInterface $entity_manager, FieldTypePluginManagerInterface $field_type_manager) {
|
||||
$plugin_definition += [
|
||||
'label' => new TranslatableMarkup('@entity_type revisions', ['@entity_type' => $storage->getEntityType()->getSingularLabel()]),
|
||||
];
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition, $migration, $storage, $bundles, $entity_manager, $field_type_manager);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@@ -78,4 +183,19 @@ class EntityRevision extends EntityContentBase {
|
||||
throw new MigrateException('This entity type does not support revisions.');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getHighestId() {
|
||||
$values = $this->storage->getQuery()
|
||||
->accessCheck(FALSE)
|
||||
->allRevisions()
|
||||
->sort($this->getKey('revision'), 'DESC')
|
||||
->range(0, 1)
|
||||
->execute();
|
||||
// The array keys are the revision IDs.
|
||||
// The array contains only one entry, so we can use key().
|
||||
return (int) key($values);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,223 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\id_map;
|
||||
|
||||
use Drupal\Core\Plugin\PluginBase;
|
||||
use Drupal\migrate\MigrateMessageInterface;
|
||||
use Drupal\migrate\Plugin\MigrateIdMapInterface;
|
||||
use Drupal\migrate\Plugin\MigrationInterface;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* Defines the null ID map implementation.
|
||||
*
|
||||
* This serves as a dummy in order to not store anything.
|
||||
*
|
||||
* @PluginID("null")
|
||||
*/
|
||||
class NullIdMap extends PluginBase implements MigrateIdMapInterface {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setMessage(MigrateMessageInterface $message) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getRowBySource(array $source_id_values) {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getRowByDestination(array $destination_id_values) {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getRowsNeedingUpdate($count) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function lookupSourceID(array $destination_id_values) {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function lookupDestinationId(array $source_id_values) {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function lookupDestinationIds(array $source_id_values) {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function saveIdMapping(Row $row, array $destination_id_values, $source_row_status = MigrateIdMapInterface::STATUS_IMPORTED, $rollback_action = MigrateIdMapInterface::ROLLBACK_DELETE) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function saveMessage(array $source_id_values, $message, $level = MigrationInterface::MESSAGE_ERROR) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getMessageIterator(array $source_id_values = [], $level = NULL) {
|
||||
return new \ArrayIterator([]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function prepareUpdate() {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function processedCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function importedCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function updateCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function errorCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function messageCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function delete(array $source_id_values, $messages_only = FALSE) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function deleteDestination(array $destination_id_values) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setUpdate(array $source_id_values) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function clearMessages() {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function destroy() {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function currentDestination() {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function currentSource() {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getQualifiedMapTableName() {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function rewind() {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function current() {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function key() {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function next() {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function valid() {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -7,6 +7,7 @@ use Drupal\Core\Field\BaseFieldDefinition;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\Core\Plugin\PluginBase;
|
||||
use Drupal\migrate\MigrateMessage;
|
||||
use Drupal\migrate\Audit\HighestIdInterface;
|
||||
use Drupal\migrate\Plugin\MigrationInterface;
|
||||
use Drupal\migrate\Event\MigrateIdMapMessageEvent;
|
||||
use Drupal\migrate\MigrateException;
|
||||
@@ -27,7 +28,7 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
*
|
||||
* @PluginID("sql")
|
||||
*/
|
||||
class Sql extends PluginBase implements MigrateIdMapInterface, ContainerFactoryPluginInterface {
|
||||
class Sql extends PluginBase implements MigrateIdMapInterface, ContainerFactoryPluginInterface, HighestIdInterface {
|
||||
|
||||
/**
|
||||
* Column name of hashed source id values.
|
||||
@@ -152,6 +153,8 @@ class Sql extends PluginBase implements MigrateIdMapInterface, ContainerFactoryP
|
||||
* The configuration for the plugin.
|
||||
* @param \Drupal\migrate\Plugin\MigrationInterface $migration
|
||||
* The migration to do.
|
||||
* @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
|
||||
* The event dispatcher.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, EventDispatcherInterface $event_dispatcher) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
@@ -693,7 +696,7 @@ class Sql extends PluginBase implements MigrateIdMapInterface, ContainerFactoryP
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function processedCount() {
|
||||
return $this->getDatabase()->select($this->mapTableName())
|
||||
return (int) $this->getDatabase()->select($this->mapTableName())
|
||||
->countQuery()
|
||||
->execute()
|
||||
->fetchField();
|
||||
@@ -703,7 +706,7 @@ class Sql extends PluginBase implements MigrateIdMapInterface, ContainerFactoryP
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function importedCount() {
|
||||
return $this->getDatabase()->select($this->mapTableName())
|
||||
return (int) $this->getDatabase()->select($this->mapTableName())
|
||||
->condition('source_row_status', [MigrateIdMapInterface::STATUS_IMPORTED, MigrateIdMapInterface::STATUS_NEEDS_UPDATE], 'IN')
|
||||
->countQuery()
|
||||
->execute()
|
||||
@@ -747,7 +750,7 @@ class Sql extends PluginBase implements MigrateIdMapInterface, ContainerFactoryP
|
||||
if (isset($status)) {
|
||||
$query->condition('source_row_status', $status);
|
||||
}
|
||||
return $query->countQuery()->execute()->fetchField();
|
||||
return (int) $query->countQuery()->execute()->fetchField();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -925,4 +928,69 @@ class Sql extends PluginBase implements MigrateIdMapInterface, ContainerFactoryP
|
||||
return $this->currentRow !== FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the migration plugin manager.
|
||||
*
|
||||
* @todo Inject as a dependency in https://www.drupal.org/node/2919158.
|
||||
*
|
||||
* @return \Drupal\migrate\Plugin\MigrationPluginManagerInterface
|
||||
* The migration plugin manager.
|
||||
*/
|
||||
protected function getMigrationPluginManager() {
|
||||
return \Drupal::service('plugin.manager.migration');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getHighestId() {
|
||||
array_filter(
|
||||
$this->migration->getDestinationPlugin()->getIds(),
|
||||
function (array $id) {
|
||||
if ($id['type'] !== 'integer') {
|
||||
throw new \LogicException('Cannot determine the highest migrated ID without an integer ID column');
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// List of mapping tables to look in for the highest ID.
|
||||
$map_tables = [
|
||||
$this->migration->id() => $this->mapTableName(),
|
||||
];
|
||||
|
||||
// If there's a bundle, it means we have a derived migration and we need to
|
||||
// find all the mapping tables from the related derived migrations.
|
||||
if ($base_id = substr($this->migration->id(), 0, strpos($this->migration->id(), static::DERIVATIVE_SEPARATOR))) {
|
||||
$migration_manager = $this->getMigrationPluginManager();
|
||||
$migrations = $migration_manager->getDefinitions();
|
||||
foreach ($migrations as $migration_id => $migration) {
|
||||
if ($migration['id'] === $base_id) {
|
||||
// Get this derived migration's mapping table and add it to the list
|
||||
// of mapping tables to look in for the highest ID.
|
||||
$stub = $migration_manager->createInstance($migration_id);
|
||||
$map_tables[$migration_id] = $stub->getIdMap()->mapTableName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the highest id from the list of map tables.
|
||||
$ids = [0];
|
||||
foreach ($map_tables as $map_table) {
|
||||
if (!$this->getDatabase()->schema()->tableExists($map_table)) {
|
||||
break;
|
||||
}
|
||||
|
||||
$query = $this->getDatabase()->select($map_table, 'map')
|
||||
->fields('map', $this->destinationIdFields())
|
||||
->range(0, 1);
|
||||
foreach (array_values($this->destinationIdFields()) as $order_field) {
|
||||
$query->orderBy($order_field, 'DESC');
|
||||
}
|
||||
$ids[] = $query->execute()->fetchField();
|
||||
}
|
||||
|
||||
// Return the highest of all the mapped IDs.
|
||||
return (int) max($ids);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,13 +15,32 @@ use Drupal\migrate\Row;
|
||||
* - from_format: The source format string as accepted by
|
||||
* @link http://php.net/manual/datetime.createfromformat.php \DateTime::createFromFormat. @endlink
|
||||
* - to_format: The destination format.
|
||||
* - timezone: String identifying the required time zone, see
|
||||
* - timezone: (deprecated) String identifying the required time zone, see
|
||||
* DateTimePlus::__construct(). The timezone configuration key is deprecated
|
||||
* in Drupal 8.4.x and will be removed before Drupal 9.0.0, use from_timezone
|
||||
* and to_timezone instead.
|
||||
* - from_timezone: String identifying the required source time zone, see
|
||||
* DateTimePlus::__construct().
|
||||
* - to_timezone: String identifying the required destination time zone, see
|
||||
* DateTimePlus::__construct().
|
||||
* - settings: keyed array of settings, see DateTimePlus::__construct().
|
||||
*
|
||||
* Configuration keys from_timezone and to_timezone are both optional. Possible
|
||||
* input variants:
|
||||
* - Both from_timezone and to_timezone are empty. Date will not be converted
|
||||
* and be treated as date in default timezone.
|
||||
* - Only from_timezone is set. Date will be converted from timezone specified
|
||||
* in from_timezone key to the default timezone.
|
||||
* - Only to_timezone is set. Date will be converted from the default timezone
|
||||
* to the timezone specified in to_timezone key.
|
||||
* - Both from_timezone and to_timezone are set. Date will be converted from
|
||||
* timezone specified in from_timezone key to the timezone specified in
|
||||
* to_timezone key.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* Example usage for date only fields (DATETIME_DATE_STORAGE_FORMAT):
|
||||
* Example usage for date only fields
|
||||
* (DateTimeItemInterface::DATE_STORAGE_FORMAT):
|
||||
* @code
|
||||
* process:
|
||||
* field_date:
|
||||
@@ -34,7 +53,8 @@ use Drupal\migrate\Row;
|
||||
* If the source value was '01/05/1955' the transformed value would be
|
||||
* 1955-01-05.
|
||||
*
|
||||
* Example usage for datetime fields (DATETIME_DATETIME_STORAGE_FORMAT):
|
||||
* Example usage for datetime fields
|
||||
* (DateTimeItemInterface::DATETIME_STORAGE_FORMAT):
|
||||
* @code
|
||||
* process:
|
||||
* field_time:
|
||||
@@ -54,7 +74,8 @@ use Drupal\migrate\Row;
|
||||
* plugin: format_date
|
||||
* from_format: 'Y-m-d\TH:i:sO'
|
||||
* to_format: 'Y-m-d\TH:i:s'
|
||||
* timezone: 'America/Managua'
|
||||
* from_timezone: 'America/Managua'
|
||||
* to_timezone: 'UTC'
|
||||
* settings:
|
||||
* validate_format: false
|
||||
* source: event_time
|
||||
@@ -65,6 +86,7 @@ use Drupal\migrate\Row;
|
||||
*
|
||||
* @see \DateTime::createFromFormat()
|
||||
* @see \Drupal\Component\Datetime\DateTimePlus::__construct()
|
||||
* @see \Drupal\datetime\Plugin\Field\FieldType\DateTimeItemInterface
|
||||
* @see \Drupal\migrate\Plugin\MigrateProcessInterface
|
||||
*
|
||||
* @MigrateProcessPlugin(
|
||||
@@ -91,14 +113,24 @@ class FormatDate extends ProcessPluginBase {
|
||||
|
||||
$fromFormat = $this->configuration['from_format'];
|
||||
$toFormat = $this->configuration['to_format'];
|
||||
$timezone = isset($this->configuration['timezone']) ? $this->configuration['timezone'] : NULL;
|
||||
if (isset($this->configuration['timezone'])) {
|
||||
@trigger_error('Configuration key "timezone" is deprecated in 8.4.x and will be removed before Drupal 9.0.0, use "from_timezone" and "to_timezone" instead. See https://www.drupal.org/node/2885746', E_USER_DEPRECATED);
|
||||
$from_timezone = $this->configuration['timezone'];
|
||||
$to_timezone = isset($this->configuration['to_timezone']) ? $this->configuration['to_timezone'] : NULL;
|
||||
}
|
||||
else {
|
||||
$system_timezone = date_default_timezone_get();
|
||||
$default_timezone = !empty($system_timezone) ? $system_timezone : 'UTC';
|
||||
$from_timezone = isset($this->configuration['from_timezone']) ? $this->configuration['from_timezone'] : $default_timezone;
|
||||
$to_timezone = isset($this->configuration['to_timezone']) ? $this->configuration['to_timezone'] : $default_timezone;
|
||||
}
|
||||
$settings = isset($this->configuration['settings']) ? $this->configuration['settings'] : [];
|
||||
|
||||
// Attempts to transform the supplied date using the defined input format.
|
||||
// DateTimePlus::createFromFormat can throw exceptions, so we need to
|
||||
// explicitly check for problems.
|
||||
try {
|
||||
$transformed = DateTimePlus::createFromFormat($fromFormat, $value, $timezone, $settings)->format($toFormat);
|
||||
$transformed = DateTimePlus::createFromFormat($fromFormat, $value, $from_timezone, $settings)->format($toFormat, ['timezone' => $to_timezone]);
|
||||
}
|
||||
catch (\InvalidArgumentException $e) {
|
||||
throw new MigrateException(sprintf('Format date plugin could not transform "%s" using the format "%s". Error: %s', $value, $fromFormat, $e->getMessage()), $e->getCode(), $e);
|
||||
|
||||
@@ -33,7 +33,7 @@ use Drupal\migrate\Row;
|
||||
* bar: foo
|
||||
* @endcode
|
||||
*
|
||||
* get also supports a list of source properties.
|
||||
* Get also supports a list of source properties.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
@@ -53,7 +53,7 @@ use Drupal\migrate\Row;
|
||||
* value will be used. This makes it impossible to reach a source property with
|
||||
* an empty string as its name.
|
||||
*
|
||||
* get also supports copying destination values. These are indicated by a
|
||||
* Get also supports copying destination values. These are indicated by a
|
||||
* starting @ sign. Values using @ must be wrapped in quotes.
|
||||
*
|
||||
* @code
|
||||
@@ -69,20 +69,18 @@ use Drupal\migrate\Row;
|
||||
* This will simply copy the destination value of foo to the destination
|
||||
* property bar. foo configuration is included for illustration purposes.
|
||||
*
|
||||
* Because of this, if your source or destination property actually starts with
|
||||
* a @ you need to double those starting characters up. This means that if a
|
||||
* destination property happens to start with a @ and you want to refer it,
|
||||
* you'll need to start with three @ characters -- one to indicate the
|
||||
* destination and two for escaping the real @.
|
||||
* Because of this, if the source or destination property actually starts with a
|
||||
* @, that character must be escaped with @@.
|
||||
* The referenced property becomes, for example, @@@foo.
|
||||
*
|
||||
* @code
|
||||
* process:
|
||||
* @foo:
|
||||
* plugin: machine_name
|
||||
* source: baz
|
||||
* bar:
|
||||
* plugin: get
|
||||
* source: '@@@foo'
|
||||
* '@foo':
|
||||
* plugin: machine_name
|
||||
* source: baz
|
||||
* bar:
|
||||
* plugin: get
|
||||
* source: '@@@foo'
|
||||
* @endcode
|
||||
*
|
||||
* This should occur extremely rarely.
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\process;
|
||||
|
||||
@trigger_error('The ' . __NAMESPACE__ . '\Iterator is deprecated in
|
||||
Drupal 8.4.x and will be removed before Drupal 9.0.0. Instead, use ' . __NAMESPACE__ . '\SubProcess', E_USER_DEPRECATED);
|
||||
@trigger_error('The ' . __NAMESPACE__ . '\Iterator is deprecated in Drupal 8.4.x and will be removed before Drupal 9.0.0. Instead, use ' . __NAMESPACE__ . '\SubProcess', E_USER_DEPRECATED);
|
||||
|
||||
/**
|
||||
* Iterates and processes an associative array.
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\process;
|
||||
|
||||
@trigger_error('The ' . __NAMESPACE__ . '\Migration is deprecated in
|
||||
Drupal 8.4.0 and will be removed before Drupal 9.0.0. Instead, use ' . __NAMESPACE__ . '\MigrationLookup', E_USER_DEPRECATED);
|
||||
@trigger_error('The ' . __NAMESPACE__ . '\Migration is deprecated in Drupal 8.4.0 and will be removed before Drupal 9.0.0. Instead, use ' . __NAMESPACE__ . '\MigrationLookup', E_USER_DEPRECATED);
|
||||
|
||||
/**
|
||||
* Calculates the value of a property based on a previous migration.
|
||||
|
||||
@@ -34,10 +34,12 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* Consider a node migration, where you want to maintain authorship. If you have
|
||||
* migrated the user accounts in a migration named "users", you would specify
|
||||
* the following:
|
||||
*
|
||||
* Consider a node migration, where you want to maintain authorship. Let's
|
||||
* assume that users are previously migrated in a migration named 'users'. The
|
||||
* 'users' migration saved the mapping between the source and destination IDs in
|
||||
* a map table. The node migration example below maps the node 'uid' property so
|
||||
* that we first take the source 'author' value and then do a lookup for the
|
||||
* corresponding Drupal user ID from the map table.
|
||||
* @code
|
||||
* process:
|
||||
* uid:
|
||||
@@ -46,15 +48,10 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
* source: author
|
||||
* @endcode
|
||||
*
|
||||
* This takes the value of the author property in the source data, and looks it
|
||||
* up in the map table associated with the users migration, returning the
|
||||
* resulting user ID and assigning it to the destination uid property.
|
||||
*
|
||||
* The value of 'migration' can be a list of migration IDs. When using multiple
|
||||
* migrations it is possible each use different source identifiers. In this
|
||||
* case one can use source_ids which is an array keyed by the migration IDs
|
||||
* and the value is a list of source properties.
|
||||
*
|
||||
* and the value is a list of source properties. See example below.
|
||||
* @code
|
||||
* process:
|
||||
* uid:
|
||||
@@ -73,8 +70,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
* map it will create a stub entity for the relationship to use. This stub is
|
||||
* generated by the migration provided. In the case of multiple migrations the
|
||||
* first value of the migration list will be used, but you can select the
|
||||
* migration you wish to use by using the stub_id configuration key:
|
||||
*
|
||||
* migration you wish to use by using the stub_id configuration key. The example
|
||||
* below uses 'members' migration to create stub entities.
|
||||
* @code
|
||||
* process:
|
||||
* uid:
|
||||
@@ -85,12 +82,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
* stub_id: members
|
||||
* @endcode
|
||||
*
|
||||
* In the above example, the value of stub_id selects the members migration to
|
||||
* create any stub entities.
|
||||
*
|
||||
* To prevent the creation of a stub entity when no relationship is found in the
|
||||
* migration map, use no_stub:
|
||||
*
|
||||
* migration map, 'no_stub' configuration can be used as shown below.
|
||||
* @code
|
||||
* process:
|
||||
* uid:
|
||||
@@ -161,10 +154,6 @@ class MigrationLookup extends ProcessPluginBase implements ContainerFactoryPlugi
|
||||
if (!is_array($migration_ids)) {
|
||||
$migration_ids = [$migration_ids];
|
||||
}
|
||||
if (!is_array($value)) {
|
||||
$value = [$value];
|
||||
}
|
||||
$this->skipOnEmpty($value);
|
||||
$self = FALSE;
|
||||
/** @var \Drupal\migrate\Plugin\MigrationInterface[] $migrations */
|
||||
$destination_ids = NULL;
|
||||
@@ -176,13 +165,15 @@ class MigrationLookup extends ProcessPluginBase implements ContainerFactoryPlugi
|
||||
}
|
||||
if (isset($this->configuration['source_ids'][$migration_id])) {
|
||||
$configuration = ['source' => $this->configuration['source_ids'][$migration_id]];
|
||||
$source_id_values[$migration_id] = $this->processPluginManager
|
||||
$value = $this->processPluginManager
|
||||
->createInstance('get', $configuration, $this->migration)
|
||||
->transform(NULL, $migrate_executable, $row, $destination_property);
|
||||
}
|
||||
else {
|
||||
$source_id_values[$migration_id] = $value;
|
||||
if (!is_array($value)) {
|
||||
$value = [$value];
|
||||
}
|
||||
$this->skipOnEmpty($value);
|
||||
$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;
|
||||
|
||||
@@ -22,8 +22,8 @@ use Drupal\migrate\MigrateSkipRowException;
|
||||
* - process: Prevents further processing of the input property when the value
|
||||
* is empty.
|
||||
* - message: (optional) A message to be logged in the {migrate_message_*} table
|
||||
* for this row. Messages are only logged for the 'row' skip level. If not
|
||||
* set, nothing is logged in the message table.
|
||||
* for this row. Messages are only logged for the 'row' method. If not set,
|
||||
* nothing is logged in the message table.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
@@ -33,11 +33,10 @@ use Drupal\migrate\MigrateSkipRowException;
|
||||
* plugin: skip_on_empty
|
||||
* method: row
|
||||
* source: field_name
|
||||
* message: 'Field field_name is missed'
|
||||
* message: 'Field field_name is missing'
|
||||
* @endcode
|
||||
*
|
||||
* If field_name is empty, skips the entire row and the message 'Field
|
||||
* field_name is missed' is logged in the message table.
|
||||
* If 'field_name' is empty, the entire row is skipped and the message 'Field
|
||||
* field_name is missing' is logged in the message table.
|
||||
*
|
||||
* @code
|
||||
* process:
|
||||
@@ -47,12 +46,13 @@ use Drupal\migrate\MigrateSkipRowException;
|
||||
* method: process
|
||||
* source: parent
|
||||
* -
|
||||
* plugin: migration
|
||||
* plugin: migration_lookup
|
||||
* migration: d6_taxonomy_term
|
||||
* @endcode
|
||||
*
|
||||
* If parent is empty, any further processing of the property is skipped - thus,
|
||||
* the next plugin (migration) will not be run.
|
||||
* If 'parent' is empty, any further processing of the property is skipped and
|
||||
* the next process plugin (migration_lookup) will not be run. Combining
|
||||
* skip_on_empty and migration_lookup is a typical process pipeline combination
|
||||
* for hierarchical entities where the root entity does not have a parent.
|
||||
*
|
||||
* @see \Drupal\migrate\Plugin\MigrateProcessInterface
|
||||
*
|
||||
|
||||
@@ -17,10 +17,10 @@ use Drupal\migrate\MigrateSkipRowException;
|
||||
*
|
||||
* Available configuration keys:
|
||||
* - source: The input value - either a scalar or an array.
|
||||
* - map: An array (of 1 or more dimensions) that identifies the mapping between
|
||||
* - map: An array (of 1 or more dimensions) that defines the mapping between
|
||||
* source values and destination values.
|
||||
* - bypass: (optional) Whether the plugin should proceed when the source is not
|
||||
* found in the map array. Defaults to FALSE.
|
||||
* found in the map array, defaults to FALSE.
|
||||
* - TRUE: Return the unmodified input value, or another default value, if one
|
||||
* is specified.
|
||||
* - FALSE: Throw a MigrateSkipRowException.
|
||||
@@ -29,6 +29,8 @@ use Drupal\migrate\MigrateSkipRowException;
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* If the value of the source property 'foo' is 'from' then the value of the
|
||||
* destination property bar will be 'to'. Similarly 'this' becomes 'that'.
|
||||
* @code
|
||||
* process:
|
||||
* bar:
|
||||
@@ -39,68 +41,75 @@ use Drupal\migrate\MigrateSkipRowException;
|
||||
* this: that
|
||||
* @endcode
|
||||
*
|
||||
* If the value of the source property foo was "from" then the value of the
|
||||
* destination property bar will be "to". Similarly "this" becomes "that".
|
||||
* static_map can do a lot more than this: it supports a list of source
|
||||
* properties. This is super useful in module-delta to machine name conversions.
|
||||
*
|
||||
* The static_map process plugin supports a list of source properties. This is
|
||||
* useful in module-delta to machine name conversions. In the example below,
|
||||
* value 'filter_url' is returned if the source property 'module' is 'filter'
|
||||
* and the source property 'delta' is '2'.
|
||||
* @code
|
||||
* process:
|
||||
* id:
|
||||
* plugin: static_map
|
||||
* source:
|
||||
* - module
|
||||
* - delta
|
||||
* map:
|
||||
* filter:
|
||||
* 0: filter_html_escape
|
||||
* 1: filter_autop
|
||||
* 2: filter_url
|
||||
* 3: filter_htmlcorrector
|
||||
* 4: filter_html_escape
|
||||
* php:
|
||||
* 0: php_code
|
||||
* source:
|
||||
* - module
|
||||
* - delta
|
||||
* map:
|
||||
* filter:
|
||||
* 0: filter_html_escape
|
||||
* 1: filter_autop
|
||||
* 2: filter_url
|
||||
* 3: filter_htmlcorrector
|
||||
* 4: filter_html_escape
|
||||
* php:
|
||||
* 0: php_code
|
||||
* @endcode
|
||||
*
|
||||
* If the value of the source properties module and delta are "filter" and "2"
|
||||
* respectively, then the returned value will be "filter_url". By default, if a
|
||||
* value is not found in the map, an exception is thrown.
|
||||
*
|
||||
* When static_map is used to just rename a few things and leave the others, a
|
||||
* "bypass: true" option can be added. In this case, the source value is used
|
||||
* unchanged, e.g.:
|
||||
*
|
||||
* When static_map is used to just rename a few values and leave the others
|
||||
* unchanged, a 'bypass: true' option can be used. See the example below. If the
|
||||
* value of the source property 'foo' is 'from', 'to' will be returned. If the
|
||||
* value of the source property 'foo' is 'another' (a value that is not in the
|
||||
* map), 'another' will be returned unchanged.
|
||||
* @code
|
||||
* process:
|
||||
* bar:
|
||||
* plugin: static_map
|
||||
* source: foo
|
||||
* map:
|
||||
* from: to
|
||||
* this: that
|
||||
* bypass: TRUE
|
||||
* map:
|
||||
* from: to
|
||||
* this: that
|
||||
* bypass: TRUE
|
||||
* @endcode
|
||||
*
|
||||
* If the value of the source property "foo" is "from" then the returned value
|
||||
* will be "to", but if the value of "foo" is "another" (a value that is not in
|
||||
* the map) then the source value is used unchanged so the returned value will
|
||||
* be "from" because "bypass" is set to TRUE.
|
||||
*
|
||||
* A default value can be defined for all values that are not included in the
|
||||
* map. See the example below. If the value of the source property 'foo' is
|
||||
* 'yet_another' (a value that is not in the map), 'bar' will be returned.
|
||||
* @code
|
||||
* process:
|
||||
* bar:
|
||||
* plugin: static_map
|
||||
* source: foo
|
||||
* map:
|
||||
* from: to
|
||||
* this: that
|
||||
* default_value: bar
|
||||
* map:
|
||||
* from: to
|
||||
* this: that
|
||||
* default_value: bar
|
||||
* @endcode
|
||||
*
|
||||
* If the value of the source property "foo" is "yet_another" (a value that is
|
||||
* not in the map) then the default_value is used so the returned value will
|
||||
* be "bar".
|
||||
* If your source data has boolean values as strings, you need to use single
|
||||
* quotes in the map. See the example below.
|
||||
* @code
|
||||
* process:
|
||||
* bar:
|
||||
* plugin: static_map
|
||||
* source: foo
|
||||
* map:
|
||||
* 'TRUE': to
|
||||
* @endcode
|
||||
*
|
||||
* Mapping from a string which contains a period is not supported. A custom
|
||||
* process plugin can be written to handle this kind of a transformation.
|
||||
* Another option which may be feasible in certain use cases is to first pass
|
||||
* the value through the machine_name process plugin.
|
||||
*
|
||||
* @see https://www.drupal.org/project/drupal/issues/2827897
|
||||
* @see \Drupal\migrate\Plugin\MigrateProcessInterface
|
||||
*
|
||||
* @MigrateProcessPlugin(
|
||||
|
||||
@@ -18,8 +18,10 @@ use Drupal\migrate\Row;
|
||||
* - key: runs the process pipeline for the key to determine a new dynamic
|
||||
* name.
|
||||
*
|
||||
* Examples:
|
||||
* Example 1:
|
||||
*
|
||||
* This example demonstrates how migration_lookup process plugin can be applied
|
||||
* on the following source data.
|
||||
* @code
|
||||
* source: Array
|
||||
* (
|
||||
@@ -41,10 +43,8 @@ use Drupal\migrate\Row;
|
||||
* )
|
||||
* ...
|
||||
* @endcode
|
||||
*
|
||||
* The sub_process process plugin will take these arrays one at a time and run
|
||||
* its own process over each one:
|
||||
*
|
||||
* its own process for each of them:
|
||||
* @code
|
||||
* process:
|
||||
* upload:
|
||||
@@ -58,16 +58,17 @@ use Drupal\migrate\Row;
|
||||
* display: list
|
||||
* description: description
|
||||
* @endcode
|
||||
*
|
||||
* In this case, each item in the upload array will be processed by the
|
||||
* sub_process process plugin. The target_id will be found by looking up the
|
||||
* destination value from a previous migration. The display and description
|
||||
* fields will simply be mapped.
|
||||
* destination value from a previous migration using the migration_lookup
|
||||
* process plugin. The display and description fields will be mapped directly.
|
||||
*
|
||||
* In the next example, normally the array returned from sub_process will have
|
||||
* its original keys. If you need to change the key, it is possible for the
|
||||
* returned array to be keyed by one of the transformed values in the sub-array.
|
||||
* Example 2.
|
||||
*
|
||||
* Drupal 6 filter formats contain a list of filters belonging to that format
|
||||
* identified by a numeric delta. A delta of 1 indicates automatic linebreaks,
|
||||
* delta of 2 indicates the URL filter and so on. This example demonstrates how
|
||||
* static_map process plugin can be applied on the following source data.
|
||||
* @code
|
||||
* source: Array
|
||||
* (
|
||||
@@ -91,7 +92,52 @@ use Drupal\migrate\Row;
|
||||
* )
|
||||
* )
|
||||
* ...
|
||||
* @endcode
|
||||
* The sub_process will take these arrays one at a time and run its own process
|
||||
* for each of them:
|
||||
* @code
|
||||
* process:
|
||||
* filters:
|
||||
* plugin: sub_process
|
||||
* source: filters
|
||||
* process:
|
||||
* id:
|
||||
* plugin: static_map
|
||||
* source:
|
||||
* - module
|
||||
* - delta
|
||||
* map:
|
||||
* filter:
|
||||
* 0: filter_html_escape
|
||||
* 1: filter_autop
|
||||
* 2: filter_url
|
||||
* 3: filter_htmlcorrector
|
||||
* 4: filter_html_escape
|
||||
* php:
|
||||
* 0: php_code
|
||||
* @endcode
|
||||
* The example above means that we take each array element ([0], [1], etc.) from
|
||||
* the source filters field and apply the static_map plugin on it. Let's have a
|
||||
* closer look at the first array at index 0:
|
||||
* @code
|
||||
* Array
|
||||
* (
|
||||
* [module] => filter
|
||||
* [delta] => 2
|
||||
* [weight] => 0
|
||||
* )
|
||||
* @endcode
|
||||
* The static_map process plugin results to value 'filter_url' for this input
|
||||
* based on the 'module' and 'delta' map.
|
||||
*
|
||||
* Example 3.
|
||||
*
|
||||
* Normally the array returned from sub_process will have its original keys. If
|
||||
* you need to change the key, it is possible for the returned array to be keyed
|
||||
* by one of the transformed values in the sub-array. For the same source data
|
||||
* used in the previous example, the migration below would result to keys
|
||||
* 'filter_2' and 'filter_0'.
|
||||
* @code
|
||||
* process:
|
||||
* filters:
|
||||
* plugin: sub_process
|
||||
@@ -106,9 +152,8 @@ use Drupal\migrate\Row;
|
||||
* delimiter: _
|
||||
* @endcode
|
||||
*
|
||||
* In the above example, the keys of the returned array would be filter_2 and
|
||||
* filter_0
|
||||
*
|
||||
* @see \Drupal\migrate\Plugin\migrate\process\MigrationLookup
|
||||
* @see \Drupal\migrate\Plugin\migrate\process\StaticMap
|
||||
* @see \Drupal\migrate\Plugin\MigrateProcessInterface
|
||||
*
|
||||
* @MigrateProcessPlugin(
|
||||
|
||||
@@ -12,19 +12,19 @@ use Drupal\Component\Utility\Unicode;
|
||||
* Returns a substring of the input value.
|
||||
*
|
||||
* The substr process plugin returns the portion of the input value specified by
|
||||
* the start and length parameters. This is a wrapper around the PHP substr()
|
||||
* function.
|
||||
* the start and length parameters. This is a wrapper around
|
||||
* \Drupal\Component\Utility\Unicode::substr().
|
||||
*
|
||||
* Available configuration keys:
|
||||
* - start: (optional) The returned string will start this many characters after
|
||||
* the beginning of the string. Defaults to NULL.
|
||||
* the beginning of the string, defaults to 0.
|
||||
* - length: (optional) The maximum number of characters in the returned
|
||||
* string. Defaults to NULL.
|
||||
* string, defaults to NULL.
|
||||
*
|
||||
* If start is NULL and length is an integer, the start position is the
|
||||
* If start is 0 and length is an integer, the start position is the
|
||||
* beginning of the string. If start is an integer and length is NULL, the
|
||||
* substring starting from the start position until the end of the string will
|
||||
* be returned. If both start and length are NULL the entire string is returned.
|
||||
* be returned. If start is 0 and length is NULL the entire string is returned.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
@@ -33,19 +33,33 @@ use Drupal\Component\Utility\Unicode;
|
||||
* new_text_field:
|
||||
* plugin: substr
|
||||
* source: some_text_field
|
||||
* start: 6
|
||||
* length: 10
|
||||
* start: 6
|
||||
* length: 10
|
||||
* @endcode
|
||||
*
|
||||
* If some_text_field was 'Marie Skłodowska Curie' then
|
||||
* $destination['new_text_field'] would be 'Skłodowska'.
|
||||
*
|
||||
* The PHP equivalent of this is:
|
||||
*
|
||||
* @code
|
||||
* $destination['new_text_field'] = substr($source['some_text_field'], 6, 10);
|
||||
* @endcode
|
||||
*
|
||||
* The substr plugin requires that the source value is not empty. If empty
|
||||
* values are expected, combine skip_on_empty process plugin to the pipeline:
|
||||
* @code
|
||||
* process:
|
||||
* new_text_field:
|
||||
* -
|
||||
* plugin: skip_on_empty
|
||||
* method: process
|
||||
* source: some_text_field
|
||||
* -
|
||||
* plugin: substr
|
||||
* source: some_text_field
|
||||
* start: 6
|
||||
* length: 10
|
||||
* @endcode
|
||||
*
|
||||
* @see \Drupal\migrate\Plugin\MigrateProcessInterface
|
||||
*
|
||||
* @MigrateProcessPlugin(
|
||||
|
||||
@@ -38,7 +38,8 @@ use Drupal\migrate\Plugin\MigrationInterface;
|
||||
* @see \Drupal\migrate\Plugin\MigrateSourceInterface
|
||||
*
|
||||
* @MigrateSource(
|
||||
* id = "embedded_data"
|
||||
* id = "embedded_data",
|
||||
* source_module = "migrate"
|
||||
* )
|
||||
*/
|
||||
class EmbeddedDataSource extends SourcePluginBase {
|
||||
@@ -108,7 +109,7 @@ class EmbeddedDataSource extends SourcePluginBase {
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function count() {
|
||||
public function count($refresh = FALSE) {
|
||||
return count($this->dataRows);
|
||||
}
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ class EmptySource extends SourcePluginBase {
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function count() {
|
||||
public function count($refresh = FALSE) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -216,8 +216,8 @@ abstract class SourcePluginBase extends PluginBase implements MigrateSourceInter
|
||||
/**
|
||||
* Initializes the iterator with the source data.
|
||||
*
|
||||
* @return array
|
||||
* An array of the data for this source.
|
||||
* @return \Iterator
|
||||
* Returns an iteratable object of data for this source.
|
||||
*/
|
||||
abstract protected function initializeIterator();
|
||||
|
||||
|
||||
@@ -346,7 +346,9 @@ abstract class SqlBase extends SourcePluginBase implements ContainerFactoryPlugi
|
||||
if (($this->batchSize > 0)) {
|
||||
$this->query->range($this->batch * $this->batchSize, $this->batchSize);
|
||||
}
|
||||
return new \IteratorIterator($this->query->execute());
|
||||
$statement = $this->query->execute();
|
||||
$statement->setFetchMode(\PDO::FETCH_ASSOC);
|
||||
return new \IteratorIterator($statement);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -379,7 +381,7 @@ abstract class SqlBase extends SourcePluginBase implements ContainerFactoryPlugi
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function count($refresh = FALSE) {
|
||||
return $this->query()->countQuery()->execute()->fetchField();
|
||||
return (int) $this->query()->countQuery()->execute()->fetchField();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -104,7 +104,7 @@ class Row {
|
||||
$this->isStub = $is_stub;
|
||||
foreach (array_keys($source_ids) as $id) {
|
||||
if (!$this->hasSourceProperty($id)) {
|
||||
throw new \InvalidArgumentException("$id has no value");
|
||||
throw new \InvalidArgumentException("$id is defined as a source ID but has no value.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user