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/Component/Plugin/Discovery/DerivativeDiscoveryDecorator.php b/core/lib/Drupal/Component/Plugin/Discovery/DerivativeDiscoveryDecorator.php index 2028f40..a5d4245 100644 --- a/core/lib/Drupal/Component/Plugin/Discovery/DerivativeDiscoveryDecorator.php +++ b/core/lib/Drupal/Component/Plugin/Discovery/DerivativeDiscoveryDecorator.php @@ -3,6 +3,7 @@ namespace Drupal\Component\Plugin\Discovery; use Drupal\Component\Plugin\Exception\InvalidDeriverException; +use Drupal\Core\Plugin\Discovery\FilterDiscoveryInterface; /** * Base class providing the tools for a plugin discovery to be derivative aware. @@ -30,6 +31,13 @@ class DerivativeDiscoveryDecorator implements DiscoveryInterface { protected $decorated; /** + * A list of filters to apply to the plugin definitions before deriving. + * + * @var \Drupal\Core\Plugin\Discovery\FilterDiscoveryInterface[] + */ + protected $filters = []; + + /** * Creates a new instance. * * @param \Drupal\Component\Plugin\Discovery\DiscoveryInterface $decorated @@ -83,6 +91,10 @@ public function getDefinition($plugin_id, $exception_on_invalid = TRUE) { */ public function getDefinitions() { $plugin_definitions = $this->decorated->getDefinitions(); + /** @var \Drupal\Core\Plugin\Discovery\FilterDiscoveryInterface $filter */ + foreach ($this->filters as $filter) { + $plugin_definitions = $filter->filter($plugin_definitions); + } return $this->getDerivatives($plugin_definitions); } @@ -241,4 +253,11 @@ public function __call($method, $args) { return call_user_func_array(array($this->decorated, $method), $args); } + /** + * @param \Drupal\Core\Plugin\Discovery\FilterDiscoveryInterface $filter + */ + public function addFilter(FilterDiscoveryInterface $filter) { + $this->filters[] = $filter; + } + } diff --git a/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php b/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php index 06365fa..93868b2 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\FilterDiscoveryByProvider; 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 (new FilterDiscoveryByProvider($this->moduleHandler->getModuleList()))->filter($definitions); } /** 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/FilterDiscoveryByProvider.php b/core/lib/Drupal/Core/Plugin/Discovery/FilterDiscoveryByProvider.php new file mode 100644 index 0000000..b438cbf --- /dev/null +++ b/core/lib/Drupal/Core/Plugin/Discovery/FilterDiscoveryByProvider.php @@ -0,0 +1,50 @@ +providers = array_keys($module_list + ['core' => TRUE, 'component' => TRUE]); + } + + /** + * Remove plugin definitions with non-existing providers. + * + * @param array $definitions + * An array of plugin definitions. + * + * @return array + * An array of plugin definitions. If a definition is an array and it has + * a provider key that provider or providers are guaranteed to exist. + */ + public function filter(array $definitions) { + 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($this->providers[$provider])) { + unset($definitions[$plugin_id]); + } + } + } + return $definitions; + } + +} diff --git a/core/lib/Drupal/Core/Plugin/Discovery/FilterDiscoveryInterface.php b/core/lib/Drupal/Core/Plugin/Discovery/FilterDiscoveryInterface.php new file mode 100644 index 0000000..15b9661 --- /dev/null +++ b/core/lib/Drupal/Core/Plugin/Discovery/FilterDiscoveryInterface.php @@ -0,0 +1,19 @@ +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) { + $definition += ['provider' => []]; + $definition['provider'] = (array) $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..12dcc4a 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\FilterDiscoveryByProvider; +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) + $this->discovery = new ContainerDerivativeDiscoveryDecorator($inherited_discovery); + $this->discovery->addFilter(new FilterDiscoveryByProvider($this->moduleHandler->getModuleList())); } return $this->discovery; }