Mercurial > hg > isophonics-drupal-site
view core/modules/migrate_drupal/src/FieldDiscovery.php @ 19:fa3358dc1485 tip
Add ndrum files
author | Chris Cannam |
---|---|
date | Wed, 28 Aug 2019 13:14:47 +0100 |
parents | af1871eacc83 |
children |
line wrap: on
line source
<?php namespace Drupal\migrate_drupal; use Drupal\Component\Plugin\Exception\PluginNotFoundException; use Drupal\Core\Logger\LoggerChannelInterface; 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\MigrateCckFieldInterface; use Drupal\migrate_drupal\Plugin\MigrateFieldPluginManagerInterface; /** * Provides field discovery for Drupal 6 & 7 migrations. */ class FieldDiscovery implements FieldDiscoveryInterface { /** * The CCK plugin manager. * * @var \Drupal\migrate_drupal\Plugin\MigrateCckFieldPluginManagerInterface */ protected $cckPluginManager; /** * 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 \Drupal\Core\Logger\LoggerChannelInterface */ 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 \Drupal\Core\Logger\LoggerChannelInterface $logger * The logger channel service. */ public function __construct(MigrateFieldPluginManagerInterface $field_plugin_manager, MigrationPluginManagerInterface $migration_plugin_manager, LoggerChannelInterface $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 = isset($plugin_definition['field_plugin_method']) ? $plugin_definition['field_plugin_method'] : 'defineValueProcessPipeline'; // @todo Remove the following 3 lines of code prior to Drupal 9.0.0. // https://www.drupal.org/node/3032317 if ($plugin instanceof MigrateCckFieldInterface) { $method = isset($plugin_definition['cck_plugin_method']) ? $plugin_definition['cck_plugin_method'] : 'processCckFieldValues'; } 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') && (empty($plugin_definition['cck_plugin_method']) || $plugin_definition['cck_plugin_method'] === 'processCckFieldValues')) { $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\MigrateCckFieldInterface|\Drupal\migrate_drupal\Plugin\MigrateFieldInterface|bool * The appropriate field or cck 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 $ex) { // @todo Replace try/catch block with $plugin = FALSE for Drupal 9. // https://www.drupal.org/project/drupal/issues/3033733 try { /** @var \Drupal\migrate_drupal\Plugin\MigrateCckFieldPluginManager $cck_plugin_manager */ $cck_plugin_manager = $this->getCckPluginManager(); $plugin_id = $cck_plugin_manager->getPluginIdFromFieldType($field_type, ['core' => $core], $migration); $plugin = $cck_plugin_manager->createInstance($plugin_id, ['core' => $core], $migration); } catch (PluginNotFoundException $ex) { $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 deprecated CCK Plugin Manager service as a BC shim. * * We don't inject this service directly because it is deprecated, and we * don't want to instantiate the plugin manager unless we have to, to avoid * triggering deprecation errors. * * @return \Drupal\migrate_drupal\Plugin\MigrateCckFieldPluginManagerInterface * The CCK Plugin Manager. */ protected function getCckPluginManager() { if (!$this->cckPluginManager) { $this->cckPluginManager = \Drupal::service('plugin.manager.migrate.cckfield'); } return $this->cckPluginManager; } /** * 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., CCK is not installed in D6 or 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 CCK or 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"); } }