class DefaultPluginManager

Same name in other branches
  1. 9 core/lib/Drupal/Core/Plugin/DefaultPluginManager.php \Drupal\Core\Plugin\DefaultPluginManager
  2. 8.9.x core/lib/Drupal/Core/Plugin/DefaultPluginManager.php \Drupal\Core\Plugin\DefaultPluginManager
  3. 10 core/lib/Drupal/Core/Plugin/DefaultPluginManager.php \Drupal\Core\Plugin\DefaultPluginManager

Base class for plugin managers.

Hierarchy

Expanded class hierarchy of DefaultPluginManager

Related topics

55 files declare their use of DefaultPluginManager
ActionManager.php in core/lib/Drupal/Core/Action/ActionManager.php
ArchiverManager.php in core/lib/Drupal/Core/Archiver/ArchiverManager.php
BlockManager.php in core/lib/Drupal/Core/Block/BlockManager.php
BreakpointManager.php in core/modules/breakpoint/src/BreakpointManager.php
CategorizingPluginManagerTraitTest.php in core/tests/Drupal/Tests/Core/Plugin/CategorizingPluginManagerTraitTest.php

... See full list

File

core/lib/Drupal/Core/Plugin/DefaultPluginManager.php, line 30

Namespace

Drupal\Core\Plugin
View source
class DefaultPluginManager extends PluginManagerBase implements PluginManagerInterface, CachedDiscoveryInterface, CacheableDependencyInterface {
    use DiscoveryCachedTrait;
    use UseCacheBackendTrait;
    
    /**
     * The cache key.
     *
     * @var string
     */
    protected $cacheKey;
    
    /**
     * An array of cache tags to use for the cached definitions.
     *
     * @var array
     */
    protected $cacheTags = [];
    
    /**
     * Name of the alter hook if one should be invoked.
     *
     * @var string
     */
    protected $alterHook;
    
    /**
     * The subdirectory within a namespace to look for plugins.
     *
     * Set to FALSE if the plugins are in the top level of the namespace.
     *
     * @var string|bool
     */
    protected $subdir;
    
    /**
     * The module handler to invoke the alter hook.
     *
     * @var \Drupal\Core\Extension\ModuleHandlerInterface
     */
    protected $moduleHandler;
    
    /**
     * The module extension list.
     *
     * @var \Drupal\Core\Extension\ModuleExtensionList
     */
    protected ?ModuleExtensionList $moduleExtensionList;
    
    /**
     * A set of defaults to be referenced by $this->processDefinition().
     *
     * Allows for additional processing of plugins when necessary or helpful for
     * development purposes.
     *
     * @var array
     */
    protected $defaults = [];
    
    /**
     * The name of the annotation that contains the plugin definition.
     *
     * @var string
     */
    protected $pluginDefinitionAnnotationName;
    
    /**
     * The name of the attribute that contains the plugin definition.
     *
     * @var string
     */
    protected $pluginDefinitionAttributeName;
    
    /**
     * The interface each plugin should implement.
     *
     * @var string|null
     */
    protected $pluginInterface;
    
    /**
     * An object of root paths that are traversable.
     *
     * The root paths are keyed by the corresponding namespace to look for plugin
     * implementations.
     *
     * @var \Traversable
     */
    protected $namespaces;
    
    /**
     * Additional annotation namespaces.
     *
     * The annotation discovery mechanism should scan these for annotation
     * definitions.
     *
     * @var string[]
     */
    protected $additionalAnnotationNamespaces = [];
    
    /**
     * Constructs a new \Drupal\Core\Plugin\DefaultPluginManager object.
     *
     * @param string|bool $subdir
     *   The plugin's subdirectory, for example Plugin/views/filter.
     * @param \Traversable $namespaces
     *   An object that implements \Traversable which contains the root paths
     *   keyed by the corresponding namespace to look for plugin implementations.
     * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
     *   The module handler.
     * @param string|null $plugin_interface
     *   (optional) The interface each plugin should implement.
     * @param string|null $plugin_definition_attribute_name
     *   (optional) The name of the attribute that contains the plugin definition.
     * @param string|array|null $plugin_definition_annotation_name
     *   (optional) The name of the annotation that contains the plugin definition.
     *   Defaults to 'Drupal\Component\Annotation\Plugin'.
     * @param string[] $additional_annotation_namespaces
     *   (optional) Additional namespaces to scan for annotation definitions.
     *
     * @todo $plugin_definition_attribute_name should default to
     * 'Drupal\Component\Plugin\Attribute\Plugin' once annotations are no longer
     * supported.
     */
    public function __construct($subdir, \Traversable $namespaces, ModuleHandlerInterface $module_handler, $plugin_interface = NULL, ?string $plugin_definition_attribute_name = NULL, string|array|null $plugin_definition_annotation_name = NULL, array $additional_annotation_namespaces = []) {
        $this->subdir = $subdir;
        $this->namespaces = $namespaces;
        $this->moduleHandler = $module_handler;
        $this->pluginInterface = $plugin_interface;
        if (is_subclass_of($plugin_definition_attribute_name, AttributeInterface::class)) {
            $this->pluginDefinitionAttributeName = $plugin_definition_attribute_name;
            $this->pluginDefinitionAnnotationName = $plugin_definition_annotation_name;
            $this->additionalAnnotationNamespaces = $additional_annotation_namespaces;
        }
        else {
            // Backward compatibility.
            $this->pluginDefinitionAnnotationName = $plugin_definition_attribute_name ?? 'Drupal\\Component\\Annotation\\Plugin';
            $this->additionalAnnotationNamespaces = $plugin_definition_annotation_name ?? [];
        }
    }
    
    /**
     * Initialize the cache backend.
     *
     * Plugin definitions are cached using the provided cache backend.
     *
     * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
     *   Cache backend instance to use.
     * @param string $cache_key
     *   Cache key prefix to use.
     * @param array $cache_tags
     *   (optional) When providing a list of cache tags, the cached plugin
     *   definitions are tagged with the provided cache tags. These cache tags can
     *   then be used to clear the corresponding cached plugin definitions. Note
     *   that this should be used with care! For clearing all cached plugin
     *   definitions of a plugin manager, call that plugin manager's
     *   clearCachedDefinitions() method. Only use cache tags when cached plugin
     *   definitions should be cleared along with other, related cache entries.
     */
    public function setCacheBackend(CacheBackendInterface $cache_backend, $cache_key, array $cache_tags = []) {
        assert(Inspector::assertAllStrings($cache_tags), 'Cache Tags must be strings.');
        $this->cacheBackend = $cache_backend;
        $this->cacheKey = $cache_key;
        $this->cacheTags = $cache_tags;
    }
    
    /**
     * Sets the alter hook name.
     *
     * @param string $alter_hook
     *   Name of the alter hook; for example, to invoke
     *   hook_my_module_data_alter() pass in "my_module_data".
     */
    protected function alterInfo($alter_hook) {
        $this->alterHook = $alter_hook;
    }
    
    /**
     * {@inheritdoc}
     */
    public function getDefinitions() {
        $definitions = $this->getCachedDefinitions();
        if (!isset($definitions)) {
            $definitions = $this->findDefinitions();
            $this->setCachedDefinitions($definitions);
        }
        return $definitions;
    }
    
    /**
     * {@inheritdoc}
     */
    public function clearCachedDefinitions() {
        if ($this->cacheBackend) {
            if ($this->cacheTags) {
                // Use the cache tags to clear the cache.
                Cache::invalidateTags($this->cacheTags);
            }
            else {
                $this->cacheBackend
                    ->delete($this->cacheKey);
            }
        }
        if ($this->discovery instanceof CachedDiscoveryInterface) {
            $this->discovery
                ->clearCachedDefinitions();
        }
        $this->definitions = NULL;
    }
    
    /**
     * Returns the cached plugin definitions of the decorated discovery class.
     *
     * @return array|null
     *   On success this will return an array of plugin definitions. On failure
     *   this should return NULL, indicating to other methods that this has not
     *   yet been defined. Success with no values should return as an empty array
     *   and would actually be returned by the getDefinitions() method.
     */
    protected function getCachedDefinitions() {
        if (!isset($this->definitions) && ($cache = $this->cacheGet($this->cacheKey))) {
            $this->definitions = $cache->data;
        }
        return $this->definitions;
    }
    
    /**
     * Sets a cache of plugin definitions for the decorated discovery class.
     *
     * @param array $definitions
     *   List of definitions to store in cache.
     */
    protected function setCachedDefinitions($definitions) {
        $this->cacheSet($this->cacheKey, $definitions, Cache::PERMANENT, $this->cacheTags);
        $this->definitions = $definitions;
    }
    
    /**
     * {@inheritdoc}
     */
    public function useCaches($use_caches = FALSE) {
        if ($this->discovery instanceof CachedDiscoveryInterface) {
            $this->discovery
                ->useCaches($use_caches);
        }
        $this->useCaches = $use_caches;
        if (!$use_caches) {
            $this->definitions = NULL;
        }
    }
    
    /**
     * Performs extra processing on plugin definitions.
     *
     * By default we add defaults for the type to the definition. If a type has
     * additional processing logic they can do that by replacing or extending the
     * method.
     */
    public function processDefinition(&$definition, $plugin_id) {
        // Only array-based definitions can have defaults merged in.
        if (is_array($definition) && !empty($this->defaults) && is_array($this->defaults)) {
            $definition = NestedArray::mergeDeep($this->defaults, $definition);
        }
        // Keep class definitions standard with no leading slash.
        if ($definition instanceof PluginDefinitionInterface) {
            assert(is_string($definition->getClass()), 'Plugin definitions must have a class');
            $definition->setClass(ltrim($definition->getClass(), '\\'));
        }
        elseif (is_array($definition) && isset($definition['class'])) {
            $definition['class'] = ltrim($definition['class'], '\\');
        }
    }
    
    /**
     * {@inheritdoc}
     */
    protected function getDiscovery() {
        if (!$this->discovery) {
            if (isset($this->pluginDefinitionAttributeName) && isset($this->pluginDefinitionAnnotationName)) {
                $discovery = new AttributeDiscoveryWithAnnotations($this->subdir, $this->namespaces, $this->pluginDefinitionAttributeName, $this->pluginDefinitionAnnotationName, $this->additionalAnnotationNamespaces);
            }
            elseif (isset($this->pluginDefinitionAttributeName)) {
                $discovery = new AttributeClassDiscovery($this->subdir, $this->namespaces, $this->pluginDefinitionAttributeName);
            }
            else {
                $discovery = new AnnotatedClassDiscovery($this->subdir, $this->namespaces, $this->pluginDefinitionAnnotationName, $this->additionalAnnotationNamespaces);
            }
            $this->discovery = new ContainerDerivativeDiscoveryDecorator($discovery);
        }
        return $this->discovery;
    }
    
    /**
     * {@inheritdoc}
     */
    protected function getFactory() {
        if (!$this->factory) {
            $this->factory = new ContainerFactory($this, $this->pluginInterface);
        }
        return $this->factory;
    }
    
    /**
     * Finds plugin definitions.
     *
     * @return array
     *   List of definitions to store in cache.
     */
    protected function findDefinitions() {
        $definitions = $this->getDiscovery()
            ->getDefinitions();
        foreach ($definitions as $plugin_id => &$definition) {
            $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) {
            $provider = $this->extractProviderFromDefinition($plugin_definition);
            if ($provider && !in_array($provider, [
                'core',
                'component',
            ]) && !$this->providerExists($provider)) {
                unset($definitions[$plugin_id]);
            }
        }
        return $definitions;
    }
    
    /**
     * Extracts the provider from a plugin definition.
     *
     * @param mixed $plugin_definition
     *   The plugin definition. Usually either an array or an instance of
     *   \Drupal\Component\Plugin\Definition\PluginDefinitionInterface
     *
     * @return string|null
     *   The provider string, if it exists. NULL otherwise.
     */
    protected function extractProviderFromDefinition($plugin_definition) {
        if ($plugin_definition instanceof PluginDefinitionInterface) {
            return $plugin_definition->getProvider();
        }
        // Attempt to convert the plugin definition to an array.
        if (is_object($plugin_definition)) {
            $plugin_definition = (array) $plugin_definition;
        }
        if (isset($plugin_definition['provider'])) {
            return $plugin_definition['provider'];
        }
    }
    
    /**
     * Invokes the hook to alter the definitions if the alter hook is set.
     *
     * @param $definitions
     *   The discovered plugin definitions.
     */
    protected function alterDefinitions(&$definitions) {
        if ($this->alterHook) {
            $this->moduleHandler
                ->alter($this->alterHook, $definitions);
        }
    }
    
    /**
     * Determines if the provider of a definition exists.
     *
     * @return bool
     *   TRUE if provider exists, FALSE otherwise.
     */
    protected function providerExists($provider) {
        return $this->moduleHandler
            ->moduleExists($provider);
    }
    
    /**
     * {@inheritdoc}
     */
    public function getCacheContexts() {
        return [];
    }
    
    /**
     * {@inheritdoc}
     */
    public function getCacheTags() {
        return $this->cacheTags;
    }
    
    /**
     * {@inheritdoc}
     */
    public function getCacheMaxAge() {
        return Cache::PERMANENT;
    }

}

Members

Title Sort descending Modifiers Object type Summary Overriden Title Overrides
DefaultPluginManager::$additionalAnnotationNamespaces protected property Additional annotation namespaces.
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::$defaults protected property A set of defaults to be referenced by $this->processDefinition(). 12
DefaultPluginManager::$moduleExtensionList protected property The module extension list.
DefaultPluginManager::$moduleHandler protected property The module handler to invoke the alter hook. 1
DefaultPluginManager::$namespaces protected property An object of root paths that are traversable.
DefaultPluginManager::$pluginDefinitionAnnotationName protected property The name of the annotation that contains the plugin definition.
DefaultPluginManager::$pluginDefinitionAttributeName protected property The name of the attribute that contains the plugin definition.
DefaultPluginManager::$pluginInterface protected property The interface each plugin should implement. 1
DefaultPluginManager::$subdir protected property The subdirectory within a namespace to look for plugins.
DefaultPluginManager::alterDefinitions protected function Invokes the hook to alter the definitions if the alter hook is set. 5
DefaultPluginManager::alterInfo protected function Sets the alter hook name.
DefaultPluginManager::clearCachedDefinitions public function Clears static and persistent plugin definition caches. Overrides CachedDiscoveryInterface::clearCachedDefinitions 11
DefaultPluginManager::extractProviderFromDefinition protected function Extracts the provider from a plugin definition.
DefaultPluginManager::findDefinitions protected function Finds plugin definitions. 7
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::getDiscovery protected function Gets the plugin discovery. Overrides PluginManagerBase::getDiscovery 17
DefaultPluginManager::getFactory protected function Gets the plugin factory. Overrides PluginManagerBase::getFactory
DefaultPluginManager::processDefinition public function Performs extra processing on plugin definitions. 15
DefaultPluginManager::providerExists protected function Determines if the provider of a definition exists. 6
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
DefaultPluginManager::__construct public function Constructs a new \Drupal\Core\Plugin\DefaultPluginManager object. 54
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
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::createInstance public function 15
PluginManagerBase::getFallbackPluginId protected function Gets a fallback id for a missing plugin. 6
PluginManagerBase::getInstance public function 6
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.
UseCacheBackendTrait::cacheSet protected function Stores data in the persistent cache, respecting the use caches flag.

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.