plus-8.x-4.x-dev/src/ProviderPluginManager.php
src/ProviderPluginManager.php
<?php
namespace Drupal\plus;
use Drupal\Component\Utility\Html;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Plugin\DefaultPluginManager;
use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
use Drupal\Core\Plugin\Discovery\ContainerDerivativeDiscoveryDecorator;
use Drupal\plus\Plugin\Discovery\AccumulativeAnnotatedClassDiscovery;
use Drupal\plus\Plugin\PluginProviderTypeInterface;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
/**
* Base class for Bootstrap plugin managers.
*
* @ingroup utility
*
* @property \Drupal\plus\Utility\ArrayObject namespaces
*/
abstract class ProviderPluginManager extends DefaultPluginManager implements ContainerAwareInterface, ContainerInjectionInterface {
use ContainerAwareTrait;
/**
* The plugin provider type.
*
* @var \Drupal\plus\Plugin\PluginProviderTypeInterface
*/
protected $providerType;
/**
* Flag indicating whether or not discovery should accumulate or replace.
*
* Enabling this means simply means that all plugin identifiers will be
* prefixed with their provider name separated by a colon, e.g.:
* "provider_name:plugin_id" instead of just "plugin_id".
*
* The primary purpose behind this level of granularity is to ensure that if
* two providers supply the same plugin identifier (often to correlate with
* another plugin identifier or hook), the current definition doesn't replace
* previous definition.
*
* This allows managers to effectively load plugins from all providers and
* then filter out which ones they need based on various getter methods below.
*
* @var bool
*/
protected $accumulativeDiscovery = FALSE;
/** @noinspection PhpMissingParentConstructorInspection */
/**
* Creates the discovery object.
*
* @param \Drupal\plus\Plugin\PluginProviderTypeInterface $provider_type
* The plugin provider type used for discovery.
* @param string|bool $subdir
* The plugin's subdirectory, for example Plugin/views/filter.
* @param string|null $plugin_interface
* (optional) The interface each plugin should implement.
* @param string $plugin_definition_annotation_name
* (optional) The name of the annotation that contains the plugin
* definition. Defaults to 'Drupal\Component\Annotation\Plugin'.
* @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
* (optional) The backend cache service to use.
* @param string[] $additional_annotation_namespaces
* (optional) Additional namespaces to scan for annotation definitions.
*/
public function __construct(PluginProviderTypeInterface $provider_type, $subdir, $plugin_interface = NULL, $plugin_definition_annotation_name = 'Drupal\Component\Annotation\Plugin', CacheBackendInterface $cache_backend = NULL, array $additional_annotation_namespaces = []) {
// Set the provider type.
$this->providerType = $provider_type;
// Set properties used for annotated discovery.
$this->subdir = $subdir;
$this->namespaces = $this->providerType->getNamespaces();
$this->pluginDefinitionAnnotationName = $plugin_definition_annotation_name;
$this->pluginInterface = $plugin_interface;
$this->additionalAnnotationNamespaces = $additional_annotation_namespaces;
// Set cache backend.
if ($cache_backend) {
$this->setCacheBackend($cache_backend, $this->generateCacheKey(), $this->getCacheTags());
}
}
/**
* {@inheritdoc}
*/
protected function alterDefinitions(&$definitions) {
if ($this->alterHook) {
$this->providerType->alterDefinitions($this->alterHook, $definitions);
}
}
/**
* Retrieves all plugin instances.
*
* @param string[] $plugin_ids
* An array of plugin identifiers to create. If empty, all defined plugin
* instances will be returned.
* @param array $configuration
* An array of configuration relevant to the plugin instance.
*
* @return object[]
* An associative array of plugin instances, keyed by plugin identifier.
*/
public function createInstances(array $plugin_ids = [], array $configuration = []) {
$instances = [];
$definitions = $this->getDefinitions();
if ($plugin_ids) {
$definitions = array_intersect_key($definitions, array_flip($plugin_ids));
}
foreach ($definitions as $plugin_id => $definition) {
$instances[$plugin_id] = $this->createInstance($plugin_id, $configuration);
}
return $instances;
}
/**
* {@inheritdoc}
*/
public function getCacheContexts() {
return $this->providerType->getCacheContexts();
}
/**
* {@inheritdoc}
*/
public function getCacheMaxAge() {
return $this->providerType->getCacheMaxAge();
}
/**
* {@inheritdoc}
*/
public function getCacheTags() {
return $this->providerType->getCacheTags();
}
/**
* Retrieves the cache identifier used for discovery.
*
* @return string
* The cache identifier.
*/
protected function generateCacheKey() {
$cid = [];
$cid[] = 'plugin.manager.' . $this->providerType->getType();
$cid[] = Html::getId((new \ReflectionClass($this))->getShortName());
$cid[] = Html::getId($this->subdir);
return implode(':', $cid);
}
/**
* {@inheritdoc}
*
* @param bool $sorted
* Flag indicating whether to sort definitions by weight.
*/
public function getDefinitions($sorted = TRUE) {
$definitions = parent::getDefinitions();
if ($sorted) {
uasort($definitions, ['\Drupal\Component\Utility\SortArray', 'sortByWeightElement']);
}
return $definitions;
}
/**
* Retrieves all definitions where the plugin ID matches a certain criteria.
*
* @param string $regex
* The regex pattern to match.
* @param bool $sorted
* Flag indicating whether to sort definitions by weight.
*
* @return array[]
* An array of plugin definitions (empty array if no definitions were
* found). Keys are plugin IDs.
*/
public function getDefinitionsLike($regex, $sorted = TRUE) {
$definitions = [];
foreach ($this->getDefinitions($sorted) as $plugin_id => $definition) {
if (preg_match($regex, $plugin_id)) {
$definitions[$plugin_id] = $definition;
}
}
return $definitions;
}
/**
* {@inheritdoc}
*/
protected function getDiscovery() {
if (!$this->discovery) {
if ($this->accumulativeDiscovery) {
$discovery = new AccumulativeAnnotatedClassDiscovery($this->subdir, $this->namespaces, $this->pluginDefinitionAnnotationName, $this->additionalAnnotationNamespaces);
}
else {
$discovery = new AnnotatedClassDiscovery($this->subdir, $this->namespaces, $this->pluginDefinitionAnnotationName, $this->additionalAnnotationNamespaces);
}
$this->discovery = new ContainerDerivativeDiscoveryDecorator($discovery);
}
return $this->discovery;
}
/**
* {@inheritdoc}
*/
protected function providerExists($provider) {
return $this->providerType->providerExists($provider);
}
}
