diff --git a/core/lib/Drupal/Component/Annotation/Plugin/Discovery/AnnotatedClassDiscovery.php b/core/lib/Drupal/Component/Annotation/Plugin/Discovery/AnnotatedClassDiscovery.php index e564fd0..f76e28e 100644 --- a/core/lib/Drupal/Component/Annotation/Plugin/Discovery/AnnotatedClassDiscovery.php +++ b/core/lib/Drupal/Component/Annotation/Plugin/Discovery/AnnotatedClassDiscovery.php @@ -142,7 +142,7 @@ public function getDefinitions() { /** @var $annotation \Drupal\Component\Annotation\AnnotationInterface */ if ($annotation = $reader->getClassAnnotation($parser->getReflectionClass(), $this->pluginDefinitionAnnotationName)) { - $this->prepareAnnotationDefinition($annotation, $class); + $this->prepareAnnotationDefinition($annotation, $class, $parser); $id = $annotation->getId(); $content = $annotation->get(); @@ -173,8 +173,10 @@ public function getDefinitions() { * The annotation derived from the plugin. * @param string $class * The class used for the plugin. + * @param \Doctrine\Common\Reflection\StaticReflectionParser $parser + * The static reflection parser. */ - protected function prepareAnnotationDefinition(AnnotationInterface $annotation, $class) { + protected function prepareAnnotationDefinition(AnnotationInterface $annotation, $class, StaticReflectionParser $parser) { $annotation->setClass($class); } diff --git a/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php b/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php index 06365fa..616933c 100644 --- a/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php +++ b/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php @@ -14,6 +14,7 @@ use Drupal\Core\Cache\Cache; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery; +use Drupal\Core\Plugin\Discovery\ProviderFilterDecorator; use Drupal\Core\Plugin\Factory\ContainerFactory; /** @@ -277,19 +278,7 @@ protected function findDefinitions() { $this->processDefinition($definition, $plugin_id); } $this->alterDefinitions($definitions); - // If this plugin was provided by a module that does not exist, remove the - // plugin definition. - foreach ($definitions as $plugin_id => $plugin_definition) { - // If the plugin definition is an object, attempt to convert it to an - // array, if that is not possible, skip further processing. - if (is_object($plugin_definition) && !($plugin_definition = (array) $plugin_definition)) { - continue; - } - if (isset($plugin_definition['provider']) && !in_array($plugin_definition['provider'], array('core', 'component')) && !$this->providerExists($plugin_definition['provider'])) { - unset($definitions[$plugin_id]); - } - } - return $definitions; + return ProviderFilterDecorator::filterDefinitions($definitions, $this->moduleHandler->getModuleList()); } /** @@ -309,6 +298,8 @@ protected function alterDefinitions(&$definitions) { * * @return bool * TRUE if provider exists, FALSE otherwise. + * + * @deprecated Will be removed in Drupal 9.0 as it is not needed now. */ protected function providerExists($provider) { return $this->moduleHandler->moduleExists($provider); diff --git a/core/lib/Drupal/Core/Plugin/Discovery/AnnotatedClassDiscovery.php b/core/lib/Drupal/Core/Plugin/Discovery/AnnotatedClassDiscovery.php index 770308d..70282d1 100644 --- a/core/lib/Drupal/Core/Plugin/Discovery/AnnotatedClassDiscovery.php +++ b/core/lib/Drupal/Core/Plugin/Discovery/AnnotatedClassDiscovery.php @@ -2,6 +2,7 @@ namespace Drupal\Core\Plugin\Discovery; +use Doctrine\Common\Reflection\StaticReflectionParser; use Drupal\Component\Annotation\AnnotationInterface; use Drupal\Component\Annotation\Plugin\Discovery\AnnotatedClassDiscovery as ComponentAnnotatedClassDiscovery; use Drupal\Component\Utility\Unicode; @@ -82,11 +83,11 @@ protected function getAnnotationReader() { /** * {@inheritdoc} */ - protected function prepareAnnotationDefinition(AnnotationInterface $annotation, $class) { - parent::prepareAnnotationDefinition($annotation, $class); + protected function prepareAnnotationDefinition(AnnotationInterface $annotation, $class, StaticReflectionParser $parser) { + parent::prepareAnnotationDefinition($annotation, $class, $parser); if (!$annotation->getProvider()) { - $annotation->setProvider($this->getProviderFromNamespace($class)); + $annotation->setProvider(static::getProviderFromNamespace($class)); } } @@ -96,10 +97,10 @@ protected function prepareAnnotationDefinition(AnnotationInterface $annotation, * @param string $namespace * The namespace to extract the provider from. * - * @return string|null + * @return null|string * The matching provider name, or NULL otherwise. */ - protected function getProviderFromNamespace($namespace) { + static public function getProviderFromNamespace($namespace) { preg_match('|^Drupal\\\\(?[\w]+)\\\\|', $namespace, $matches); if (isset($matches['provider'])) { diff --git a/core/lib/Drupal/Core/Plugin/Discovery/AnnotatedClassDiscoveryAutomatedProviders.php b/core/lib/Drupal/Core/Plugin/Discovery/AnnotatedClassDiscoveryAutomatedProviders.php new file mode 100644 index 0000000..e750713 --- /dev/null +++ b/core/lib/Drupal/Core/Plugin/Discovery/AnnotatedClassDiscoveryAutomatedProviders.php @@ -0,0 +1,29 @@ +getProvider(); + parent::prepareAnnotationDefinition($annotation, $class, $parser); + + if (!$provider_set) { + $namespaces[$annotation->getProvider()] = TRUE; + foreach ($parser->getUseStatements() as $class) { + if ($namespace = AnnotatedClassDiscovery::getProviderFromNamespace($class)) { + $namespaces[strtolower($namespace)] = TRUE; + } + } + $annotation->setProvider(array_keys($namespaces)); + } + } + +} diff --git a/core/lib/Drupal/Core/Plugin/Discovery/ProviderFilterDecorator.php b/core/lib/Drupal/Core/Plugin/Discovery/ProviderFilterDecorator.php new file mode 100644 index 0000000..75aeb86 --- /dev/null +++ b/core/lib/Drupal/Core/Plugin/Discovery/ProviderFilterDecorator.php @@ -0,0 +1,81 @@ +decorated = $decorated; + $this->providers = $module_list + ['core' => TRUE, 'component' => TRUE]; + } + + /** + * Remove plugin definitions with non-existing providers. + * + * @param mixed[] $definitions + * An array of plugin definitions (empty array if no definitions were + * found). Keys are plugin IDs. + * @param array $providers + * An associative array whose keys are the names of the modules. + */ + public static function filterDefinitions(array $definitions, array $providers) { + foreach ($definitions as $plugin_id => $plugin_definition) { + // If the plugin definition is an object, attempt to convert it to an + // array, if that is not possible, skip further processing. + if ((is_object($plugin_definition) && !($plugin_definition = (array) $plugin_definition)) || !isset($plugin_definition['provider'])) { + continue; + } + foreach ((array) $plugin_definition['provider'] as $provider) { + if (!isset($providers[$provider])) { + unset($definitions[$plugin_id]); + } + } + } + } + + /** + * {@inheritdoc} + */ + public function getDefinitions() { + return static::filterDefinitions($this->decorated->getDefinitions(), $this->providers); + } + + /** + * Passes through all unknown calls onto the decorated object. + */ + public function __call($method, $args) { + return call_user_func_array(array($this->decorated, $method), $args); + } + + +} diff --git a/core/modules/migrate/migrate.services.yml b/core/modules/migrate/migrate.services.yml index da43b38..254de2a 100644 --- a/core/modules/migrate/migrate.services.yml +++ b/core/modules/migrate/migrate.services.yml @@ -6,7 +6,7 @@ services: factory: cache_factory:get arguments: [migrate] plugin.manager.migrate.source: - class: Drupal\migrate\Plugin\MigratePluginManager + class: Drupal\migrate\Plugin\MigrateSourcePluginManager arguments: [source, '@container.namespaces', '@cache.discovery', '@module_handler', 'Drupal\migrate\Annotation\MigrateSource'] plugin.manager.migrate.process: class: Drupal\migrate\Plugin\MigratePluginManager diff --git a/core/modules/migrate/src/Plugin/InheritProviderDecorator.php b/core/modules/migrate/src/Plugin/InheritProviderDecorator.php new file mode 100644 index 0000000..bb51f50 --- /dev/null +++ b/core/modules/migrate/src/Plugin/InheritProviderDecorator.php @@ -0,0 +1,52 @@ +decorated = $decorated; + } + + /** + * {@inheritdoc} + */ + public function getDefinitions() { + $source_plugin_manager = \Drupal::service('plugin.manager.migrate.source'); + return array_map(function (array $definition) use ($source_plugin_manager) { + if (!isset($definition['provider'])) { + $source_plugin_definition = $source_plugin_manager->getDefinition($definition['source']['plugin']); + if (isset($source_plugin_definition['provider'])) { + $definition['provider'] = array_merge($definition['provider'], $source_plugin_definition['provider']); + } + } + return $definition; + }, $this->decorated->getDefinitions()); + } + + /** + * Passes through all unknown calls onto the decorated object. + */ + public function __call($method, $args) { + return call_user_func_array(array($this->decorated, $method), $args); + } + +} diff --git a/core/modules/migrate/src/Plugin/MigrateSourcePluginManager.php b/core/modules/migrate/src/Plugin/MigrateSourcePluginManager.php new file mode 100644 index 0000000..8a688aa --- /dev/null +++ b/core/modules/migrate/src/Plugin/MigrateSourcePluginManager.php @@ -0,0 +1,19 @@ +discovery) { + $discovery = new AnnotatedClassDiscoveryAutomatedProviders($this->subdir, $this->namespaces, $this->pluginDefinitionAnnotationName, $this->additionalAnnotationNamespaces); + $this->discovery = new ContainerDerivativeDiscoveryDecorator($discovery); + } + return $this->discovery; + } + +} + diff --git a/core/modules/migrate/src/Plugin/MigrationPluginManager.php b/core/modules/migrate/src/Plugin/MigrationPluginManager.php index d082c11..ba2ea0b 100644 --- a/core/modules/migrate/src/Plugin/MigrationPluginManager.php +++ b/core/modules/migrate/src/Plugin/MigrationPluginManager.php @@ -9,6 +9,8 @@ use Drupal\Core\Language\LanguageManagerInterface; use Drupal\Core\Plugin\DefaultPluginManager; use Drupal\Core\Plugin\Discovery\ContainerDerivativeDiscoveryDecorator; +use Drupal\Core\Plugin\Discovery\ProviderFilterDecorator; +use Drupal\Core\Plugin\Discovery\ProviderAwareContainerDerivativeDiscoveryDecorator; use Drupal\Core\Plugin\Discovery\YamlDirectoryDiscovery; use Drupal\Core\Plugin\Factory\ContainerFactory; use Drupal\migrate\MigrateBuildDependencyInterface; @@ -68,7 +70,9 @@ protected function getDiscovery() { }, $this->moduleHandler->getModuleDirectories()); $yaml_discovery = new YamlDirectoryDiscovery($directories, 'migrate'); - $this->discovery = new ContainerDerivativeDiscoveryDecorator($yaml_discovery); + $inherited_discovery = new InheritProviderDecorator($yaml_discovery); + $filtered_discovery = new ProviderFilterDecorator($inherited_discovery, $this->moduleHandler->getModuleList()); + $this->discovery = new ContainerDerivativeDiscoveryDecorator($filtered_discovery); } return $this->discovery; }