FieldDiscovery.php
Same filename in other branches
Namespace
Drupal\migrate_drupalFile
-
core/
modules/ migrate_drupal/ src/ FieldDiscovery.php
View source
<?php
namespace Drupal\migrate_drupal;
use Drupal\Component\Plugin\Exception\PluginNotFoundException;
use Drupal\migrate\Exception\RequirementsException;
use Drupal\migrate\Plugin\MigrationInterface;
use Drupal\migrate\Plugin\MigrationPluginManagerInterface;
use Drupal\migrate\Plugin\RequirementsInterface;
use Drupal\migrate_drupal\Plugin\MigrateFieldPluginManagerInterface;
use Psr\Log\LoggerInterface;
/**
* Provides field discovery for Drupal 6 & 7 migrations.
*/
class FieldDiscovery implements FieldDiscoveryInterface {
/**
* An array of already discovered field plugin information.
*
* @var array
*/
protected $fieldPluginCache;
/**
* The field plugin manager.
*
* @var \Drupal\migrate_drupal\Plugin\MigrateFieldPluginManagerInterface
*/
protected $fieldPluginManager;
/**
* The migration plugin manager.
*
* @var \Drupal\migrate\Plugin\MigrationPluginManagerInterface
*/
protected $migrationPluginManager;
/**
* The logger channel service.
*
* @var \Psr\Log\LoggerInterface
*/
protected $logger;
/**
* A cache of discovered fields.
*
* It is an array of arrays. If the entity type is bundleable, a third level
* of arrays is added to account for fields discovered at the bundle level.
*
* [{core}][{entity_type}][{bundle}]
*
* @var array
*/
protected $discoveredFieldsCache = [];
/**
* An array of bundle keys, keyed by drupal core version.
*
* In Drupal 6, only nodes were fieldable, and the bundles were called
* 'type_name'. In Drupal 7, everything became entities, and the more
* generic 'bundle' was used.
*
* @var array
*/
protected $bundleKeys = [
FieldDiscoveryInterface::DRUPAL_6 => 'type_name',
FieldDiscoveryInterface::DRUPAL_7 => 'bundle',
];
/**
* An array of source plugin ids, keyed by Drupal core version.
*
* @var array
*/
protected $sourcePluginIds = [
FieldDiscoveryInterface::DRUPAL_6 => 'd6_field_instance',
FieldDiscoveryInterface::DRUPAL_7 => 'd7_field_instance',
];
/**
* An array of supported Drupal core versions.
*
* @var array
*/
protected $supportedCoreVersions = [
FieldDiscoveryInterface::DRUPAL_6,
FieldDiscoveryInterface::DRUPAL_7,
];
/**
* Constructs a FieldDiscovery object.
*
* @param \Drupal\migrate_drupal\Plugin\MigrateFieldPluginManagerInterface $field_plugin_manager
* The field plugin manager.
* @param \Drupal\migrate\Plugin\MigrationPluginManagerInterface $migration_plugin_manager
* The migration plugin manager.
* @param \Psr\Log\LoggerInterface $logger
* The logger channel service.
*/
public function __construct(MigrateFieldPluginManagerInterface $field_plugin_manager, MigrationPluginManagerInterface $migration_plugin_manager, LoggerInterface $logger) {
$this->fieldPluginManager = $field_plugin_manager;
$this->migrationPluginManager = $migration_plugin_manager;
$this->logger = $logger;
}
/**
* {@inheritdoc}
*/
public function addAllFieldProcesses(MigrationInterface $migration) {
$core = $this->getCoreVersion($migration);
$fields = $this->getAllFields($core);
foreach ($fields as $entity_type_id => $bundle) {
$this->addEntityFieldProcesses($migration, $entity_type_id);
}
}
/**
* {@inheritdoc}
*/
public function addEntityFieldProcesses(MigrationInterface $migration, $entity_type_id) {
$core = $this->getCoreVersion($migration);
$fields = $this->getAllFields($core);
if (!empty($fields[$entity_type_id]) && is_array($fields[$entity_type_id])) {
foreach ($fields[$entity_type_id] as $bundle => $fields) {
$this->addBundleFieldProcesses($migration, $entity_type_id, $bundle);
}
}
}
/**
* {@inheritdoc}
*/
public function addBundleFieldProcesses(MigrationInterface $migration, $entity_type_id, $bundle) {
$core = $this->getCoreVersion($migration);
$fields = $this->getAllFields($core);
$plugin_definition = $migration->getPluginDefinition();
if (empty($fields[$entity_type_id][$bundle])) {
return;
}
$bundle_fields = $fields[$entity_type_id][$bundle];
foreach ($bundle_fields as $field_name => $field_info) {
$plugin = $this->getFieldPlugin($field_info['type'], $migration);
if ($plugin) {
$method = $plugin_definition['field_plugin_method'] ?? 'defineValueProcessPipeline';
call_user_func_array([
$plugin,
$method,
], [
$migration,
$field_name,
$field_info,
]);
}
else {
// Default to a get process plugin if this is a value migration.
if (empty($plugin_definition['field_plugin_method']) || $plugin_definition['field_plugin_method'] === 'defineValueProcessPipeline') {
$migration->setProcessOfProperty($field_name, $field_name);
}
}
}
}
/**
* Returns the appropriate field plugin for a given field type.
*
* @param string $field_type
* The field type.
* @param \Drupal\migrate\Plugin\MigrationInterface $migration
* The migration to retrieve the plugin for.
*
* @return \Drupal\migrate_drupal\Plugin\MigrateFieldInterface|bool
* The appropriate field plugin to process this field type.
*
* @throws \Drupal\Component\Plugin\Exception\PluginException
* @throws \InvalidArgumentException
*/
protected function getFieldPlugin($field_type, MigrationInterface $migration) {
$core = $this->getCoreVersion($migration);
if (!isset($this->fieldPluginCache[$core][$field_type])) {
try {
$plugin_id = $this->fieldPluginManager
->getPluginIdFromFieldType($field_type, [
'core' => $core,
], $migration);
$plugin = $this->fieldPluginManager
->createInstance($plugin_id, [
'core' => $core,
], $migration);
} catch (PluginNotFoundException) {
$plugin = FALSE;
}
$this->fieldPluginCache[$core][$field_type] = $plugin;
}
return $this->fieldPluginCache[$core][$field_type];
}
/**
* Gets all field information related to this migration.
*
* @param string $core
* The Drupal core version to get fields for.
*
* @return array
* A multidimensional array of source data from the relevant field instance
* migration, keyed first by entity type, then by bundle and finally by
* field name.
*/
protected function getAllFields($core) {
if (empty($this->discoveredFieldsCache[$core])) {
$this->discoveredFieldsCache[$core] = [];
$source_plugin = $this->getSourcePlugin($core);
foreach ($source_plugin as $row) {
/** @var \Drupal\migrate\Row $row */
if ($core === FieldDiscoveryInterface::DRUPAL_7) {
$entity_type_id = $row->get('entity_type');
}
else {
$entity_type_id = 'node';
}
$bundle = $row->getSourceProperty($this->bundleKeys[$core]);
$this->discoveredFieldsCache[$core][$entity_type_id][$bundle][$row->getSourceProperty('field_name')] = $row->getSource();
}
}
return $this->discoveredFieldsCache[$core];
}
/**
* Gets all field information for a particular entity type.
*
* @param string $core
* The Drupal core version.
* @param string $entity_type_id
* The legacy entity type ID.
*
* @return array
* A multidimensional array of source data from the relevant field instance
* migration for the entity type, keyed first by bundle and then by field
* name.
*/
protected function getEntityFields($core, $entity_type_id) {
$fields = $this->getAllFields($core);
if (!empty($fields[$entity_type_id])) {
return $fields[$entity_type_id];
}
return [];
}
/**
* Gets all field information for a particular entity type and bundle.
*
* @param string $core
* The Drupal core version.
* @param string $entity_type_id
* The legacy entity type ID.
* @param string $bundle
* The legacy bundle (or content_type).
*
* @return array
* An array of source data from the relevant field instance migration for
* the bundle, keyed by field name.
*/
protected function getBundleFields($core, $entity_type_id, $bundle) {
$fields = $this->getEntityFields($core, $entity_type_id);
if (!empty($fields[$bundle])) {
return $fields[$bundle];
}
return [];
}
/**
* Gets the source plugin to use to gather field information.
*
* @param string $core
* The Drupal core version.
*
* @return array|\Drupal\migrate\Plugin\MigrateSourceInterface
* The source plugin, or an empty array if none can be found that meets
* requirements.
*/
protected function getSourcePlugin($core) {
$definition = $this->getFieldInstanceStubMigrationDefinition($core);
$source_plugin = $this->migrationPluginManager
->createStubMigration($definition)
->getSourcePlugin();
if ($source_plugin instanceof RequirementsInterface) {
try {
$source_plugin->checkRequirements();
} catch (RequirementsException $e) {
// If checkRequirements() failed, the source database did not support
// fields (i.e., Field is not installed in D7). Therefore, $fields will
// be empty and below we'll return an empty array. The migration will
// proceed without adding fields.
$this->logger
->notice('Field discovery failed for Drupal core version @core. Did this site have the Field module installed? Error: @message', [
'@core' => $core,
'@message' => $e->getMessage(),
]);
return [];
}
}
return $source_plugin;
}
/**
* Provides the stub migration definition for a given Drupal core version.
*
* @param string $core
* The Drupal core version.
*
* @return array
* The stub migration definition.
*/
protected function getFieldInstanceStubMigrationDefinition($core) {
return [
'destination' => [
'plugin' => 'null',
],
'idMap' => [
'plugin' => 'null',
],
'source' => [
'ignore_map' => TRUE,
'plugin' => $this->sourcePluginIds[$core],
],
];
}
/**
* Finds the core version of a Drupal migration.
*
* @param \Drupal\migrate\Plugin\MigrationInterface $migration
* The migration.
*
* @return string|bool
* A string representation of the Drupal version, or FALSE.
*
* @throws \InvalidArgumentException
*/
protected function getCoreVersion(MigrationInterface $migration) {
$tags = $migration->getMigrationTags();
if (in_array('Drupal 7', $tags, TRUE)) {
return FieldDiscoveryInterface::DRUPAL_7;
}
elseif (in_array('Drupal 6', $tags, TRUE)) {
return FieldDiscoveryInterface::DRUPAL_6;
}
throw new \InvalidArgumentException("Drupal Core version not found for this migration");
}
}
Classes
Title | Deprecated | Summary |
---|---|---|
FieldDiscovery | Provides field discovery for Drupal 6 & 7 migrations. |
Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.