"Fossies" - the Fresh Open Source Software Archive

Member "drupal-8.9.10/core/modules/migrate_drupal/src/FieldDiscovery.php" (26 Nov 2020, 12946 Bytes) of package /linux/www/drupal-8.9.10.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) PHP source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "FieldDiscovery.php" see the Fossies "Dox" file reference documentation.

    1 <?php
    2 
    3 namespace Drupal\migrate_drupal;
    4 
    5 use Drupal\Component\Plugin\Exception\PluginNotFoundException;
    6 use Drupal\migrate\Exception\RequirementsException;
    7 use Drupal\migrate\Plugin\MigrationInterface;
    8 use Drupal\migrate\Plugin\MigrationPluginManagerInterface;
    9 use Drupal\migrate\Plugin\RequirementsInterface;
   10 use Drupal\migrate_drupal\Plugin\MigrateCckFieldInterface;
   11 use Drupal\migrate_drupal\Plugin\MigrateFieldPluginManagerInterface;
   12 use Psr\Log\LoggerInterface;
   13 
   14 /**
   15  * Provides field discovery for Drupal 6 & 7 migrations.
   16  */
   17 class FieldDiscovery implements FieldDiscoveryInterface {
   18 
   19   /**
   20    * The CCK plugin manager.
   21    *
   22    * @var \Drupal\migrate_drupal\Plugin\MigrateCckFieldPluginManagerInterface
   23    */
   24   protected $cckPluginManager;
   25 
   26   /**
   27    * An array of already discovered field plugin information.
   28    *
   29    * @var array
   30    */
   31   protected $fieldPluginCache;
   32 
   33   /**
   34    * The field plugin manager.
   35    *
   36    * @var \Drupal\migrate_drupal\Plugin\MigrateFieldPluginManagerInterface
   37    */
   38   protected $fieldPluginManager;
   39 
   40   /**
   41    * The migration plugin manager.
   42    *
   43    * @var \Drupal\migrate\Plugin\MigrationPluginManagerInterface
   44    */
   45   protected $migrationPluginManager;
   46 
   47   /**
   48    * The logger channel service.
   49    *
   50    * @var \Psr\Log\LoggerInterface
   51    */
   52   protected $logger;
   53 
   54   /**
   55    * A cache of discovered fields.
   56    *
   57    * It is an array of arrays. If the entity type is bundleable, a third level
   58    * of arrays is added to account for fields discovered at the bundle level.
   59    *
   60    * [{core}][{entity_type}][{bundle}]
   61    *
   62    * @var array
   63    */
   64   protected $discoveredFieldsCache = [];
   65 
   66   /**
   67    * An array of bundle keys, keyed by drupal core version.
   68    *
   69    * In Drupal 6, only nodes were fieldable, and the bundles were called
   70    * 'type_name'.  In Drupal 7, everything became entities, and the more
   71    * generic 'bundle' was used.
   72    *
   73    * @var array
   74    */
   75   protected $bundleKeys = [
   76     FieldDiscoveryInterface::DRUPAL_6 => 'type_name',
   77     FieldDiscoveryInterface::DRUPAL_7 => 'bundle',
   78   ];
   79 
   80   /**
   81    * An array of source plugin ids, keyed by Drupal core version.
   82    *
   83    * @var array
   84    */
   85   protected $sourcePluginIds = [
   86     FieldDiscoveryInterface::DRUPAL_6 => 'd6_field_instance',
   87     FieldDiscoveryInterface::DRUPAL_7 => 'd7_field_instance',
   88   ];
   89 
   90   /**
   91    * An array of supported Drupal core versions.
   92    *
   93    * @var array
   94    */
   95   protected $supportedCoreVersions = [
   96     FieldDiscoveryInterface::DRUPAL_6,
   97     FieldDiscoveryInterface::DRUPAL_7,
   98   ];
   99 
  100   /**
  101    * Constructs a FieldDiscovery object.
  102    *
  103    * @param \Drupal\migrate_drupal\Plugin\MigrateFieldPluginManagerInterface $field_plugin_manager
  104    *   The field plugin manager.
  105    * @param \Drupal\migrate\Plugin\MigrationPluginManagerInterface $migration_plugin_manager
  106    *   The migration plugin manager.
  107    * @param \Psr\Log\LoggerInterface $logger
  108    *   The logger channel service.
  109    */
  110   public function __construct(MigrateFieldPluginManagerInterface $field_plugin_manager, MigrationPluginManagerInterface $migration_plugin_manager, LoggerInterface $logger) {
  111     $this->fieldPluginManager = $field_plugin_manager;
  112     $this->migrationPluginManager = $migration_plugin_manager;
  113     $this->logger = $logger;
  114   }
  115 
  116   /**
  117    * {@inheritdoc}
  118    */
  119   public function addAllFieldProcesses(MigrationInterface $migration) {
  120     $core = $this->getCoreVersion($migration);
  121     $fields = $this->getAllFields($core);
  122     foreach ($fields as $entity_type_id => $bundle) {
  123       $this->addEntityFieldProcesses($migration, $entity_type_id);
  124     }
  125   }
  126 
  127   /**
  128    * {@inheritdoc}
  129    */
  130   public function addEntityFieldProcesses(MigrationInterface $migration, $entity_type_id) {
  131     $core = $this->getCoreVersion($migration);
  132     $fields = $this->getAllFields($core);
  133     if (!empty($fields[$entity_type_id])  && is_array($fields[$entity_type_id])) {
  134       foreach ($fields[$entity_type_id] as $bundle => $fields) {
  135         $this->addBundleFieldProcesses($migration, $entity_type_id, $bundle);
  136       }
  137     }
  138   }
  139 
  140   /**
  141    * {@inheritdoc}
  142    */
  143   public function addBundleFieldProcesses(MigrationInterface $migration, $entity_type_id, $bundle) {
  144     $core = $this->getCoreVersion($migration);
  145     $fields = $this->getAllFields($core);
  146     $plugin_definition = $migration->getPluginDefinition();
  147     if (empty($fields[$entity_type_id][$bundle])) {
  148       return;
  149     }
  150     $bundle_fields = $fields[$entity_type_id][$bundle];
  151     foreach ($bundle_fields as $field_name => $field_info) {
  152       $plugin = $this->getFieldPlugin($field_info['type'], $migration);
  153       if ($plugin) {
  154         $method = isset($plugin_definition['field_plugin_method']) ? $plugin_definition['field_plugin_method'] : 'defineValueProcessPipeline';
  155 
  156         // @todo Remove the following 3 lines of code prior to Drupal 9.0.0.
  157         // https://www.drupal.org/node/3032317
  158         if ($plugin instanceof MigrateCckFieldInterface) {
  159           $method = isset($plugin_definition['cck_plugin_method']) ? $plugin_definition['cck_plugin_method'] : 'processCckFieldValues';
  160         }
  161 
  162         call_user_func_array([
  163           $plugin,
  164           $method,
  165         ], [
  166           $migration,
  167           $field_name,
  168           $field_info,
  169         ]);
  170       }
  171       else {
  172         // Default to a get process plugin if this is a value migration.
  173         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')) {
  174           $migration->setProcessOfProperty($field_name, $field_name);
  175         }
  176       }
  177     }
  178   }
  179 
  180   /**
  181    * Returns the appropriate field plugin for a given field type.
  182    *
  183    * @param string $field_type
  184    *   The field type.
  185    * @param \Drupal\migrate\Plugin\MigrationInterface $migration
  186    *   The migration to retrieve the plugin for.
  187    *
  188    * @return \Drupal\migrate_drupal\Plugin\MigrateCckFieldInterface|\Drupal\migrate_drupal\Plugin\MigrateFieldInterface|bool
  189    *   The appropriate field or cck plugin to process this field type.
  190    *
  191    * @throws \Drupal\Component\Plugin\Exception\PluginException
  192    * @throws \InvalidArgumentException
  193    */
  194   protected function getFieldPlugin($field_type, MigrationInterface $migration) {
  195     $core = $this->getCoreVersion($migration);
  196     if (!isset($this->fieldPluginCache[$core][$field_type])) {
  197       try {
  198         $plugin_id = $this->fieldPluginManager->getPluginIdFromFieldType($field_type, ['core' => $core], $migration);
  199         $plugin = $this->fieldPluginManager->createInstance($plugin_id, ['core' => $core], $migration);
  200       }
  201       catch (PluginNotFoundException $ex) {
  202         // @todo Replace try/catch block with $plugin = FALSE for Drupal 9.
  203         // https://www.drupal.org/project/drupal/issues/3033733
  204         try {
  205           /** @var \Drupal\migrate_drupal\Plugin\MigrateCckFieldPluginManager $cck_plugin_manager */
  206           $cck_plugin_manager = $this->getCckPluginManager();
  207           $plugin_id = $cck_plugin_manager->getPluginIdFromFieldType($field_type, ['core' => $core], $migration);
  208           $plugin = $cck_plugin_manager->createInstance($plugin_id, ['core' => $core], $migration);
  209         }
  210         catch (PluginNotFoundException $ex) {
  211           $plugin = FALSE;
  212         }
  213       }
  214       $this->fieldPluginCache[$core][$field_type] = $plugin;
  215     }
  216     return $this->fieldPluginCache[$core][$field_type];
  217   }
  218 
  219   /**
  220    * Gets all field information related to this migration.
  221    *
  222    * @param string $core
  223    *   The Drupal core version to get fields for.
  224    *
  225    * @return array
  226    *   A multidimensional array of source data from the relevant field instance
  227    *   migration, keyed first by entity type, then by bundle and finally by
  228    *   field name.
  229    */
  230   protected function getAllFields($core) {
  231     if (empty($this->discoveredFieldsCache[$core])) {
  232       $this->discoveredFieldsCache[$core] = [];
  233       $source_plugin = $this->getSourcePlugin($core);
  234       foreach ($source_plugin as $row) {
  235         /** @var \Drupal\migrate\Row $row */
  236         if ($core === FieldDiscoveryInterface::DRUPAL_7) {
  237           $entity_type_id = $row->get('entity_type');
  238         }
  239         else {
  240           $entity_type_id = 'node';
  241         }
  242         $bundle = $row->getSourceProperty($this->bundleKeys[$core]);
  243         $this->discoveredFieldsCache[$core][$entity_type_id][$bundle][$row->getSourceProperty('field_name')] = $row->getSource();
  244       }
  245     }
  246     return $this->discoveredFieldsCache[$core];
  247   }
  248 
  249   /**
  250    * Gets all field information for a particular entity type.
  251    *
  252    * @param string $core
  253    *   The Drupal core version.
  254    * @param string $entity_type_id
  255    *   The legacy entity type ID.
  256    *
  257    * @return array
  258    *   A multidimensional array of source data from the relevant field instance
  259    *   migration for the entity type, keyed first by bundle and then by field
  260    *   name.
  261    */
  262   protected function getEntityFields($core, $entity_type_id) {
  263     $fields = $this->getAllFields($core);
  264     if (!empty($fields[$entity_type_id])) {
  265       return $fields[$entity_type_id];
  266     }
  267     return [];
  268   }
  269 
  270   /**
  271    * Gets all field information for a particular entity type and bundle.
  272    *
  273    * @param string $core
  274    *   The Drupal core version.
  275    * @param string $entity_type_id
  276    *   The legacy entity type ID.
  277    * @param string $bundle
  278    *   The legacy bundle (or content_type).
  279    *
  280    * @return array
  281    *   An array of source data from the relevant field instance migration for
  282    *   the bundle, keyed by field name.
  283    */
  284   protected function getBundleFields($core, $entity_type_id, $bundle) {
  285     $fields = $this->getEntityFields($core, $entity_type_id);
  286     if (!empty($fields[$bundle])) {
  287       return $fields[$bundle];
  288     }
  289     return [];
  290   }
  291 
  292   /**
  293    * Gets the deprecated CCK Plugin Manager service as a BC shim.
  294    *
  295    * We don't inject this service directly because it is deprecated, and we
  296    * don't want to instantiate the plugin manager unless we have to, to avoid
  297    * triggering deprecation errors.
  298    *
  299    * @return \Drupal\migrate_drupal\Plugin\MigrateCckFieldPluginManagerInterface
  300    *   The CCK Plugin Manager.
  301    */
  302   protected function getCckPluginManager() {
  303     if (!$this->cckPluginManager) {
  304       $this->cckPluginManager = \Drupal::service('plugin.manager.migrate.cckfield');
  305     }
  306     return $this->cckPluginManager;
  307   }
  308 
  309   /**
  310    * Gets the source plugin to use to gather field information.
  311    *
  312    * @param string $core
  313    *   The Drupal core version.
  314    *
  315    * @return array|\Drupal\migrate\Plugin\MigrateSourceInterface
  316    *   The source plugin, or an empty array if none can be found that meets
  317    *   requirements.
  318    */
  319   protected function getSourcePlugin($core) {
  320     $definition = $this->getFieldInstanceStubMigrationDefinition($core);
  321     $source_plugin = $this->migrationPluginManager
  322       ->createStubMigration($definition)
  323       ->getSourcePlugin();
  324     if ($source_plugin instanceof RequirementsInterface) {
  325       try {
  326         $source_plugin->checkRequirements();
  327       }
  328       catch (RequirementsException $e) {
  329         // If checkRequirements() failed, the source database did not support
  330         // fields (i.e., CCK is not installed in D6 or Field is not installed in
  331         // D7). Therefore, $fields will be empty and below we'll return an empty
  332         // array. The migration will proceed without adding fields.
  333         $this->logger->notice('Field discovery failed for Drupal core version @core. Did this site have the CCK or Field module installed? Error: @message', [
  334           '@core' => $core,
  335           '@message' => $e->getMessage(),
  336         ]);
  337         return [];
  338       }
  339     }
  340     return $source_plugin;
  341   }
  342 
  343   /**
  344    * Provides the stub migration definition for a given Drupal core version.
  345    *
  346    * @param string $core
  347    *   The Drupal core version.
  348    *
  349    * @return array
  350    *   The stub migration definition.
  351    */
  352   protected function getFieldInstanceStubMigrationDefinition($core) {
  353     return [
  354       'destination' => ['plugin' => 'null'],
  355       'idMap' => ['plugin' => 'null'],
  356       'source' => [
  357         'ignore_map' => TRUE,
  358         'plugin' => $this->sourcePluginIds[$core],
  359       ],
  360     ];
  361   }
  362 
  363   /**
  364    * Finds the core version of a Drupal migration.
  365    *
  366    * @param \Drupal\migrate\Plugin\MigrationInterface $migration
  367    *   The migration.
  368    *
  369    * @return string|bool
  370    *   A string representation of the Drupal version, or FALSE.
  371    *
  372    * @throws \InvalidArgumentException
  373    */
  374   protected function getCoreVersion(MigrationInterface $migration) {
  375     $tags = $migration->getMigrationTags();
  376     if (in_array('Drupal 7', $tags, TRUE)) {
  377       return FieldDiscoveryInterface::DRUPAL_7;
  378     }
  379     elseif (in_array('Drupal 6', $tags, TRUE)) {
  380       return FieldDiscoveryInterface::DRUPAL_6;
  381     }
  382     throw new \InvalidArgumentException("Drupal Core version not found for this migration");
  383   }
  384 
  385 }