You are here

class MigrationPluginManager in Drupal 8

Same name in this branch
  1. 8 core/modules/migrate_drupal/src/MigrationPluginManager.php \Drupal\migrate_drupal\MigrationPluginManager
  2. 8 core/modules/migrate/src/Plugin/MigrationPluginManager.php \Drupal\migrate\Plugin\MigrationPluginManager
Same name and namespace in other branches
  1. 9 core/modules/migrate/src/Plugin/MigrationPluginManager.php \Drupal\migrate\Plugin\MigrationPluginManager

Plugin manager for migration plugins.

Hierarchy

Expanded class hierarchy of MigrationPluginManager

2 files declare their use of MigrationPluginManager
MigrationPluginManager.php in core/modules/migrate_drupal/src/MigrationPluginManager.php
MigrationPluginManagerTest.php in core/modules/migrate/tests/src/Unit/MigrationPluginManagerTest.php
1 string reference to 'MigrationPluginManager'
migrate.services.yml in core/modules/migrate/migrate.services.yml
core/modules/migrate/migrate.services.yml
1 service uses MigrationPluginManager
plugin.manager.migration in core/modules/migrate/migrate.services.yml
Drupal\migrate\Plugin\MigrationPluginManager

File

core/modules/migrate/src/Plugin/MigrationPluginManager.php, line 20

Namespace

Drupal\migrate\Plugin
View source
class MigrationPluginManager extends DefaultPluginManager implements MigrationPluginManagerInterface, MigrateBuildDependencyInterface {

  /**
   * Provides default values for migrations.
   *
   * @var array
   */
  protected $defaults = [
    'class' => '\\Drupal\\migrate\\Plugin\\Migration',
  ];

  /**
   * The interface the plugins should implement.
   *
   * @var string
   */
  protected $pluginInterface = 'Drupal\\migrate\\Plugin\\MigrationInterface';

  /**
   * The module handler.
   *
   * @var \Drupal\Core\Extension\ModuleHandlerInterface
   */
  protected $moduleHandler;

  /**
   * Construct a migration plugin manager.
   *
   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
   *   The module handler.
   * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
   *   The cache backend for the definitions.
   * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
   *   The language manager.
   */
  public function __construct(ModuleHandlerInterface $module_handler, CacheBackendInterface $cache_backend, LanguageManagerInterface $language_manager) {
    $this->factory = new ContainerFactory($this, $this->pluginInterface);
    $this
      ->alterInfo('migration_plugins');
    $this
      ->setCacheBackend($cache_backend, 'migration_plugins', [
      'migration_plugins',
    ]);
    $this->moduleHandler = $module_handler;
  }

  /**
   * 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());
      $yaml_discovery = new YamlDirectoryDiscovery($directories, 'migrate');

      // This gets rid of migrations which try to use a non-existent source
      // plugin. The common case for this is if the source plugin has, or
      // specifies, a non-existent provider.
      $only_with_source_discovery = new NoSourcePluginDecorator($yaml_discovery);

      // This gets rid of migrations with explicit providers set if one of the
      // providers do not exist before we try to use a potentially non-existing
      // deriver. This is a rare case.
      $filtered_discovery = new ProviderFilterDecorator($only_with_source_discovery, [
        $this->moduleHandler,
        'moduleExists',
      ]);
      $this->discovery = new ContainerDerivativeDiscoveryDecorator($filtered_discovery);
    }
    return $this->discovery;
  }

  /**
   * {@inheritdoc}
   */
  public function createInstance($plugin_id, array $configuration = []) {
    $instances = $this
      ->createInstances([
      $plugin_id,
    ], [
      $plugin_id => $configuration,
    ]);
    return reset($instances);
  }

  /**
   * {@inheritdoc}
   */
  public function createInstances($migration_id, array $configuration = []) {
    if (empty($migration_id)) {
      $migration_id = array_keys($this
        ->getDefinitions());
    }
    $factory = $this
      ->getFactory();
    $migration_ids = (array) $migration_id;
    $plugin_ids = $this
      ->expandPluginIds($migration_ids);
    $instances = [];
    foreach ($plugin_ids as $plugin_id) {
      $instances[$plugin_id] = $factory
        ->createInstance($plugin_id, isset($configuration[$plugin_id]) ? $configuration[$plugin_id] : []);
    }
    foreach ($instances as $migration) {
      $migration
        ->set('migration_dependencies', array_map([
        $this,
        'expandPluginIds',
      ], $migration
        ->getMigrationDependencies()));
    }

    // Sort the migrations based on their dependencies.
    return $this
      ->buildDependencyMigration($instances, []);
  }

  /**
   * {@inheritdoc}
   */
  public function createInstancesByTag($tag) {
    $migrations = array_filter($this
      ->getDefinitions(), function ($migration) use ($tag) {
      return !empty($migration['migration_tags']) && in_array($tag, $migration['migration_tags']);
    });
    return $this
      ->createInstances(array_keys($migrations));
  }

  /**
   * Expand derivative migration dependencies.
   *
   * We need to expand any derivative migrations. Derivative migrations are
   * calculated by migration derivers such as D6NodeDeriver. This allows
   * migrations to depend on the base id and then have a dependency on all
   * derivative migrations. For example, d6_comment depends on d6_node but after
   * we've expanded the dependencies it will depend on d6_node:page,
   * d6_node:story and so on, for other derivative migrations.
   *
   * @return array
   *   An array of expanded plugin ids.
   */
  protected function expandPluginIds(array $migration_ids) {
    $plugin_ids = [];
    foreach ($migration_ids as $id) {
      $plugin_ids += preg_grep('/^' . preg_quote($id, '/') . PluginBase::DERIVATIVE_SEPARATOR . '/', array_keys($this
        ->getDefinitions()));
      if ($this
        ->hasDefinition($id)) {
        $plugin_ids[] = $id;
      }
    }
    return $plugin_ids;
  }

  /**
   * {@inheritdoc}
   */
  public function buildDependencyMigration(array $migrations, array $dynamic_ids) {

    // Migration dependencies can be optional or required. If an optional
    // dependency does not run, the current migration is still OK to go. Both
    // optional and required dependencies (if run at all) must run before the
    // current migration.
    $dependency_graph = [];
    $required_dependency_graph = [];
    $have_optional = FALSE;
    foreach ($migrations as $migration) {

      /** @var \Drupal\migrate\Plugin\MigrationInterface $migration */
      $id = $migration
        ->id();
      $requirements[$id] = [];
      $dependency_graph[$id]['edges'] = [];
      $migration_dependencies = $migration
        ->getMigrationDependencies();
      if (isset($migration_dependencies['required'])) {
        foreach ($migration_dependencies['required'] as $dependency) {
          if (!isset($dynamic_ids[$dependency])) {
            $this
              ->addDependency($required_dependency_graph, $id, $dependency, $dynamic_ids);
          }
          $this
            ->addDependency($dependency_graph, $id, $dependency, $dynamic_ids);
        }
      }
      if (!empty($migration_dependencies['optional'])) {
        foreach ($migration_dependencies['optional'] as $dependency) {
          $this
            ->addDependency($dependency_graph, $id, $dependency, $dynamic_ids);
        }
        $have_optional = TRUE;
      }
    }
    $dependency_graph = (new Graph($dependency_graph))
      ->searchAndSort();
    if ($have_optional) {
      $required_dependency_graph = (new Graph($required_dependency_graph))
        ->searchAndSort();
    }
    else {
      $required_dependency_graph = $dependency_graph;
    }
    $weights = [];
    foreach ($migrations as $migration_id => $migration) {

      // Populate a weights array to use with array_multisort() later.
      $weights[] = $dependency_graph[$migration_id]['weight'];
      if (!empty($required_dependency_graph[$migration_id]['paths'])) {
        $migration
          ->set('requirements', $required_dependency_graph[$migration_id]['paths']);
      }
    }

    // Sort weights, labels, and keys in the same order as each other.
    array_multisort($weights, SORT_DESC, SORT_NUMERIC, array_keys($migrations), SORT_ASC, SORT_NATURAL, $migrations);
    return $migrations;
  }

  /**
   * Add one or more dependencies to a graph.
   *
   * @param array $graph
   *   The graph so far, passed by reference.
   * @param int $id
   *   The migration ID.
   * @param string $dependency
   *   The dependency string.
   * @param array $dynamic_ids
   *   The dynamic ID mapping.
   */
  protected function addDependency(array &$graph, $id, $dependency, $dynamic_ids) {
    $dependencies = isset($dynamic_ids[$dependency]) ? $dynamic_ids[$dependency] : [
      $dependency,
    ];
    if (!isset($graph[$id]['edges'])) {
      $graph[$id]['edges'] = [];
    }
    $graph[$id]['edges'] += array_combine($dependencies, $dependencies);
  }

  /**
   * {@inheritdoc}
   */
  public function createStubMigration(array $definition) {
    $id = isset($definition['id']) ? $definition['id'] : uniqid();
    return Migration::create(\Drupal::getContainer(), [], $id, $definition);
  }

  /**
   * Finds plugin definitions.
   *
   * @return array
   *   List of definitions to store in cache.
   *
   * @todo This is a temporary solution to the fact that migration source
   *   plugins have more than one provider. This functionality will be moved to
   *   core in https://www.drupal.org/node/2786355.
   */
  protected function findDefinitions() {
    $definitions = $this
      ->getDiscovery()
      ->getDefinitions();
    foreach ($definitions as $plugin_id => &$definition) {
      $this
        ->processDefinition($definition, $plugin_id);
    }
    $this
      ->alterDefinitions($definitions);
    return ProviderFilterDecorator::filterDefinitions($definitions, function ($provider) {
      return $this
        ->providerExists($provider);
    });
  }

}

Members

Namesort descending Modifiers Type Description Overrides
DefaultPluginManager::$additionalAnnotationNamespaces protected property Additional namespaces the annotation discovery mechanism should scan for annotation definitions.
DefaultPluginManager::$alterHook protected property Name of the alter hook if one should be invoked.
DefaultPluginManager::$cacheKey protected property The cache key.
DefaultPluginManager::$cacheTags protected property An array of cache tags to use for the cached definitions.
DefaultPluginManager::$namespaces protected property An object that implements \Traversable which contains the root paths keyed by the corresponding namespace to look for plugin implementations.
DefaultPluginManager::$pluginDefinitionAnnotationName protected property The name of the annotation that contains the plugin definition.
DefaultPluginManager::$subdir protected property The subdirectory within a namespace to look for plugins, or FALSE if the plugins are in the top level of the namespace.
DefaultPluginManager::alterDefinitions protected function Invokes the hook to alter the definitions if the alter hook is set. 1
DefaultPluginManager::alterInfo protected function Sets the alter hook name.
DefaultPluginManager::clearCachedDefinitions public function Clears static and persistent plugin definition caches. Overrides CachedDiscoveryInterface::clearCachedDefinitions 5
DefaultPluginManager::extractProviderFromDefinition protected function Extracts the provider from a plugin definition.
DefaultPluginManager::fixContextAwareDefinitions private function Fix the definitions of context-aware plugins.
DefaultPluginManager::getCacheContexts public function The cache contexts associated with this object. Overrides CacheableDependencyInterface::getCacheContexts
DefaultPluginManager::getCachedDefinitions protected function Returns the cached plugin definitions of the decorated discovery class.
DefaultPluginManager::getCacheMaxAge public function The maximum age for which this object may be cached. Overrides CacheableDependencyInterface::getCacheMaxAge
DefaultPluginManager::getCacheTags public function The cache tags associated with this object. Overrides CacheableDependencyInterface::getCacheTags
DefaultPluginManager::getDefinitions public function Gets the definition of all plugins for this type. Overrides DiscoveryTrait::getDefinitions 2
DefaultPluginManager::getFactory protected function Gets the plugin factory. Overrides PluginManagerBase::getFactory
DefaultPluginManager::processDefinition public function Performs extra processing on plugin definitions. 13
DefaultPluginManager::providerExists protected function Determines if the provider of a definition exists. 3
DefaultPluginManager::setCacheBackend public function Initialize the cache backend.
DefaultPluginManager::setCachedDefinitions protected function Sets a cache of plugin definitions for the decorated discovery class.
DefaultPluginManager::useCaches public function Disable the use of caches. Overrides CachedDiscoveryInterface::useCaches 1
DiscoveryCachedTrait::$definitions protected property Cached definitions array. 1
DiscoveryCachedTrait::getDefinition public function Overrides DiscoveryTrait::getDefinition 3
DiscoveryTrait::doGetDefinition protected function Gets a specific plugin definition.
DiscoveryTrait::hasDefinition public function
MigrationPluginManager::$defaults protected property Provides default values for migrations. Overrides DefaultPluginManager::$defaults
MigrationPluginManager::$moduleHandler protected property The module handler. Overrides DefaultPluginManager::$moduleHandler
MigrationPluginManager::$pluginInterface protected property The interface the plugins should implement. Overrides DefaultPluginManager::$pluginInterface
MigrationPluginManager::addDependency protected function Add one or more dependencies to a graph.
MigrationPluginManager::buildDependencyMigration public function Builds a dependency tree for the migrations and set their order. Overrides MigrateBuildDependencyInterface::buildDependencyMigration
MigrationPluginManager::createInstance public function Creates a pre-configured instance of a plugin. Overrides PluginManagerBase::createInstance
MigrationPluginManager::createInstances public function Create pre-configured instance of plugin derivatives. Overrides MigrationPluginManagerInterface::createInstances
MigrationPluginManager::createInstancesByTag public function Create migrations given a tag. Overrides MigrationPluginManagerInterface::createInstancesByTag
MigrationPluginManager::createStubMigration public function Creates a stub migration plugin from a definition array. Overrides MigrationPluginManagerInterface::createStubMigration
MigrationPluginManager::expandPluginIds protected function Expand derivative migration dependencies.
MigrationPluginManager::findDefinitions protected function Finds plugin definitions. Overrides DefaultPluginManager::findDefinitions
MigrationPluginManager::getDiscovery protected function Gets the plugin discovery. Overrides DefaultPluginManager::getDiscovery
MigrationPluginManager::__construct public function Construct a migration plugin manager. Overrides DefaultPluginManager::__construct 1
PluginManagerBase::$discovery protected property The object that discovers plugins managed by this manager.
PluginManagerBase::$factory protected property The object that instantiates plugins managed by this manager.
PluginManagerBase::$mapper protected property The object that returns the preconfigured plugin instance appropriate for a particular runtime condition.
PluginManagerBase::getInstance public function Gets a preconfigured instance of a plugin. Overrides MapperInterface::getInstance 7
PluginManagerBase::handlePluginNotFound protected function Allows plugin managers to specify custom behavior if a plugin is not found. 1
UseCacheBackendTrait::$cacheBackend protected property Cache backend instance.
UseCacheBackendTrait::$useCaches protected property Flag whether caches should be used or skipped.
UseCacheBackendTrait::cacheGet protected function Fetches from the cache backend, respecting the use caches flag. 1
UseCacheBackendTrait::cacheSet protected function Stores data in the persistent cache, respecting the use caches flag.