Commit fb7ad824 authored by alexpott's avatar alexpott

Issue #1903346 by Berdir, tim.plunkett, EclipseGc: Establish a new...

Issue #1903346 by Berdir, tim.plunkett, EclipseGc: Establish a new DefaultPluginManager to encapsulate best practices.
parent d1ae4a05
......@@ -153,7 +153,7 @@ services:
arguments: ['@container.namespaces', '@service_container']
plugin.manager.archiver:
class: Drupal\Core\Archiver\ArchiverManager
arguments: ['@container.namespaces']
arguments: ['@container.namespaces', '@cache.cache', '@language_manager', '@module_handler']
plugin.manager.action:
class: Drupal\Core\Action\ActionManager
arguments: ['@container.namespaces']
......@@ -192,7 +192,7 @@ services:
- [setValidationConstraintManager, ['@validation.constraint']]
validation.constraint:
class: Drupal\Core\Validation\ConstraintManager
arguments: ['@container.namespaces']
arguments: ['@container.namespaces', '@cache.cache', '@language_manager', '@module_handler']
lock:
class: Drupal\Core\Lock\DatabaseLockBackend
user.tempstore:
......@@ -423,7 +423,7 @@ services:
arguments: ['@database', '@request']
plugin.manager.condition:
class: Drupal\Core\Condition\ConditionManager
arguments: ['@container.namespaces']
arguments: ['@container.namespaces', '@cache.cache', '@language_manager', '@module_handler']
kernel_destruct_subscriber:
class: Drupal\Core\EventSubscriber\KernelDestructionSubscriber
tags:
......@@ -436,7 +436,7 @@ services:
- { name: event_subscriber }
image.toolkit.manager:
class: Drupal\system\Plugin\ImageToolkitManager
arguments: ['@container.namespaces']
arguments: ['@container.namespaces', '@cache.cache', '@language_manager']
image.toolkit:
class: Drupal\system\Plugin\ImageToolkitInterface
factory_method: getDefaultToolkit
......
......@@ -7,27 +7,33 @@
namespace Drupal\Core\Archiver;
use Drupal\Component\Plugin\Factory\DefaultFactory;
use Drupal\Component\Plugin\PluginManagerBase;
use Drupal\Core\Plugin\Discovery\AlterDecorator;
use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
use Drupal\Core\Plugin\Discovery\CacheDecorator;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Language\LanguageManager;
use Drupal\Core\Plugin\DefaultPluginManager;
/**
* Archiver plugin manager.
*/
class ArchiverManager extends PluginManagerBase {
class ArchiverManager extends DefaultPluginManager {
/**
* Constructs a ArchiverManager object.
*
* @param \Traversable $namespaces
* An object that implements \Traversable which contains the root paths
* keyed by the corresponding namespace to look for plugin implementations,
* keyed by the corresponding namespace to look for plugin implementations.
* @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
* Cache backend instance to use.
* @param \Drupal\Core\Language\LanguageManager $language_manager
* The language manager.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler to invoke the alter hook with.
*/
public function __construct(\Traversable $namespaces) {
$this->discovery = new AnnotatedClassDiscovery('Archiver', $namespaces);
$this->discovery = new AlterDecorator($this->discovery, 'archiver_info');
$this->discovery = new CacheDecorator($this->discovery, 'archiver_info');
public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, LanguageManager $language_manager, ModuleHandlerInterface $module_handler) {
parent::__construct('Archiver', $namespaces);
$this->alterInfo($module_handler, 'archiver_info');
$this->setCacheBackend($cache_backend, $language_manager, 'archiver_info');
}
/**
......
......@@ -7,35 +7,35 @@
namespace Drupal\Core\Condition;
use Drupal\Component\Plugin\PluginManagerBase;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Executable\ExecutableManagerInterface;
use Drupal\Core\Executable\ExecutableInterface;
use Drupal\Component\Plugin\Factory\DefaultFactory;
use Drupal\Component\Plugin\Discovery\DerivativeDiscoveryDecorator;
use Drupal\Core\Language\Language;
use Drupal\Core\Plugin\Discovery\AlterDecorator;
use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
use Drupal\Core\Plugin\Discovery\CacheDecorator;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Language\LanguageManager;
use Drupal\Core\Plugin\DefaultPluginManager;
/**
* A plugin manager for condition plugins.
*/
class ConditionManager extends PluginManagerBase implements ExecutableManagerInterface {
class ConditionManager extends DefaultPluginManager implements ExecutableManagerInterface {
/**
* Constructs aa ConditionManager object.
* Constructs a ConditionManager object.
*
* @param \Traversable $namespaces
* An object that implements \Traversable which contains the root paths
* keyed by the corresponding namespace to look for plugin implementations,
* keyed by the corresponding namespace to look for plugin implementations.
* @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
* Cache backend instance to use.
* @param \Drupal\Core\Language\LanguageManager $language_manager
* The language manager.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler to invoke the alter hook with.
*/
public function __construct(\Traversable $namespaces) {
$this->discovery = new AnnotatedClassDiscovery('Condition', $namespaces);
$this->discovery = new DerivativeDiscoveryDecorator($this->discovery);
$this->discovery = new AlterDecorator($this->discovery, 'condition_info');
$this->discovery = new CacheDecorator($this->discovery, 'condition:' . language(Language::TYPE_INTERFACE)->langcode);
$this->factory = new DefaultFactory($this);
public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, LanguageManager $language_manager, ModuleHandlerInterface $module_handler) {
parent::__construct('Condition', $namespaces);
$this->alterInfo($module_handler, 'condition_info');
$this->setCacheBackend($cache_backend, $language_manager, 'condition');
}
/**
......
<?php
/**
* @file
* Contains \Drupal\Core\Plugin\DefaultPluginManager
*/
namespace Drupal\Core\Plugin;
use Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface;
use Drupal\Component\Plugin\Discovery\DerivativeDiscoveryDecorator;
use Drupal\Component\Plugin\PluginManagerBase;
use Drupal\Component\Plugin\PluginManagerInterface;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Language\LanguageManager;
use Drupal\Core\Language\Language;
use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
use Drupal\Core\Plugin\Factory\ContainerFactory;
/**
* Base class for plugin managers.
*/
class DefaultPluginManager extends PluginManagerBase implements PluginManagerInterface, CachedDiscoveryInterface {
/**
* Cached definitions array.
*
* @var array
*/
protected $definitions;
/**
* Cache backend instance.
*
* @var \Drupal\Core\Cache\CacheBackendInterface
*/
protected $cacheBackend;
/**
* Provided cache key prefix.
*
* @var string
*/
protected $cacheKeyPrefix;
/**
* Actually used cache key with the language code appended.
*
* @var string
*/
protected $cacheKey;
/**
* Name of the alter hook if one should be invoked.
*
* @var string
*/
protected $alterHook;
/**
* The plugin's subdirectory, for example views/filter.
*
* @var string
*/
protected $subdir;
/**
* The module handler to invoke the alter hook.
*
* @var \Drupal\Core\Extension\ModuleHandlerInterface
*/
protected $moduleHandler;
/**
* The language manager.
*
* @var \Drupal\Core\Language\LanguageManager
*/
protected $languageManager;
/**
* Creates the discovery object.
*
* @param string $subdir
* The plugin's subdirectory, for example 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 array $annotation_namespaces
* (optional) The namespaces of classes that can be used as annotations.
* Defaults to an empty array.
* @param string $plugin_definition_annotation_name
* (optional) The name of the annotation that contains the plugin definition.
* Defaults to 'Drupal\Component\Annotation\Plugin'.
*/
public function __construct($subdir, \Traversable $namespaces, $annotation_namespaces = array(), $plugin_definition_annotation_name = 'Drupal\Component\Annotation\Plugin') {
$this->subdir = $subdir;
$this->discovery = new AnnotatedClassDiscovery($subdir, $namespaces, $annotation_namespaces, $plugin_definition_annotation_name);
$this->discovery = new DerivativeDiscoveryDecorator($this->discovery);
$this->factory = new ContainerFactory($this);
}
/**
* Initialize the cache backend.
*
* Plugin definitions are cached using the provided cache backend. The
* interface language is added as a suffix to the cache key.
*
* @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
* Cache backend instance to use.
* @param \Drupal\Core\Language\LanguageManager
* The language manager.
* @param string $cache_key_prefix
* Cache key prefix to use, the language code will be appended
* automatically.
*/
public function setCacheBackend(CacheBackendInterface $cache_backend, LanguageManager $language_manager, $cache_key_prefix) {
$this->languageManager = $language_manager;
$this->cacheBackend = $cache_backend;
$this->cacheKeyPrefix = $cache_key_prefix;
$this->cacheKey = $cache_key_prefix . ':' . $language_manager->getLanguage(Language::TYPE_INTERFACE)->langcode;
}
/**
* Initializes the alter hook.
*
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler to invoke the alter hook with.
* @param string $alter_hook
* Name of the alter hook.
*/
protected function alterInfo(ModuleHandlerInterface $module_handler, $alter_hook) {
$this->moduleHandler = $module_handler;
$this->alterHook = $alter_hook;
}
/**
* {@inheritdoc}
*/
public function getDefinition($plugin_id) {
// Fetch definitions if they're not loaded yet.
if (!isset($this->definitions)) {
$this->getDefinitions();
}
// Avoid using a ternary that would create a copy of the array.
if (isset($this->definitions[$plugin_id])) {
return $this->definitions[$plugin_id];
}
return array();
}
/**
* {@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) {
$cache_keys = array();
// @todo: Use $this->languageManager->languageList() after http://drupal.org/node/1862202 is in.
foreach (language_list() as $langcode => $language) {
$cache_keys[] = $this->cacheKeyPrefix . ':' .$langcode;
}
$this->cacheBackend->deleteMultiple($cache_keys);
}
$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) && $this->cacheBackend && $cache = $this->cacheBackend->get($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) {
if ($this->cacheBackend) {
$this->cacheBackend->set($this->cacheKey, $definitions);
}
$this->definitions = $definitions;
}
/**
* Finds plugin definitions.
*
* @return array
* List of definitions to store in cache.
*/
protected function findDefinitions() {
$definitions = $this->discovery->getDefinitions();
foreach ($definitions as $plugin_id => &$definition) {
$this->processDefinition($definition, $plugin_id);
}
if ($this->alterHook) {
$this->moduleHandler->alter($this->alterHook, $definitions);
}
return $definitions;
}
}
......@@ -7,15 +7,11 @@
namespace Drupal\Core\Validation;
use Drupal\Component\Plugin\Factory\DefaultFactory;
use Drupal\Component\Plugin\PluginManagerBase;
use Drupal\Component\Plugin\Discovery\StaticDiscoveryDecorator;
use Drupal\Component\Plugin\Discovery\DerivativeDiscoveryDecorator;
use Drupal\Component\Plugin\Discovery\ProcessDecorator;
use Drupal\Core\Language\Language;
use Drupal\Core\Plugin\Discovery\AlterDecorator;
use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
use Drupal\Core\Plugin\Discovery\CacheDecorator;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Language\LanguageManager;
use Drupal\Core\Plugin\DefaultPluginManager;
/**
* Constraint plugin manager.
......@@ -35,24 +31,26 @@
* types FALSE may be specified. The key defaults to an empty array, i.e. no
* types are supported.
*/
class ConstraintManager extends PluginManagerBase {
class ConstraintManager extends DefaultPluginManager {
/**
* Overrides \Drupal\Component\Plugin\PluginManagerBase::__construct().
*
* @param \Traversable $namespaces
* An object that implements \Traversable which contains the root paths
* keyed by the corresponding namespace to look for plugin implementations,
* keyed by the corresponding namespace to look for plugin implementations.
* @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
* Cache backend instance to use.
* @param \Drupal\Core\Language\LanguageManager $language_manager
* The language manager.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler to invoke the alter hook with.
*/
public function __construct(\Traversable $namespaces) {
$this->discovery = new AnnotatedClassDiscovery('Validation/Constraint', $namespaces);
public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, LanguageManager $language_manager, ModuleHandlerInterface $module_handler) {
parent::__construct('Validation/Constraint', $namespaces);
$this->discovery = new StaticDiscoveryDecorator($this->discovery, array($this, 'registerDefinitions'));
$this->discovery = new DerivativeDiscoveryDecorator($this->discovery);
$this->discovery = new ProcessDecorator($this->discovery, array($this, 'processDefinition'));
$this->discovery = new AlterDecorator($this->discovery, 'validation_constraint');
$this->discovery = new CacheDecorator($this->discovery, 'validation_constraints:' . language(Language::TYPE_INTERFACE)->langcode);
$this->factory = new DefaultFactory($this);
$this->alterInfo($module_handler, 'validation_constraint');
$this->setCacheBackend($cache_backend, $language_manager, 'validation_constraint');
}
/**
......
services:
plugin.manager.block:
class: Drupal\block\Plugin\Type\BlockManager
arguments: ['@container.namespaces']
arguments: ['@container.namespaces', '@cache.block', '@language_manager', '@module_handler']
cache.block:
class: Drupal\Core\Cache\CacheBackendInterface
tags:
......
......@@ -6,15 +6,10 @@
namespace Drupal\block\Plugin\Type;
use Drupal\Component\Plugin\PluginManagerBase;
use Drupal\Component\Plugin\Discovery\DerivativeDiscoveryDecorator;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Language\Language;
use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
use Drupal\Core\Plugin\Discovery\AlterDecorator;
use Drupal\Core\Plugin\Discovery\CacheDecorator;
use Drupal\Component\Plugin\Factory\DefaultFactory;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Language\LanguageManager;
use Drupal\Core\Plugin\DefaultPluginManager;
/**
* Manages discovery and instantiation of block plugins.
*
......@@ -22,22 +17,24 @@
*
* @see \Drupal\block\BlockPluginInterface
*/
class BlockManager extends PluginManagerBase {
class BlockManager extends DefaultPluginManager {
/**
* Constructs a new \Drupal\block\Plugin\Type\BlockManager object.
*
* @param \Traversable $namespaces
* An object that implements \Traversable which contains the root paths
* keyed by the corresponding namespace to look for plugin implementations,
* keyed by the corresponding namespace to look for plugin implementations.
* @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
* Cache backend instance to use.
* @param \Drupal\Core\Language\LanguageManager $language_manager
* The language manager.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler to invoke the alter hook with.
*/
public function __construct(\Traversable $namespaces) {
$this->discovery = new AnnotatedClassDiscovery('Block', $namespaces);
$this->discovery = new DerivativeDiscoveryDecorator($this->discovery);
$this->discovery = new AlterDecorator($this->discovery, 'block');
$this->discovery = new CacheDecorator($this->discovery, 'block_plugins:' . language(Language::TYPE_INTERFACE)->langcode, 'block', CacheBackendInterface::CACHE_PERMANENT, array('block'));
$this->factory = new DefaultFactory($this->discovery);
public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, LanguageManager $language_manager, ModuleHandlerInterface $module_handler) {
parent::__construct('Block', $namespaces);
$this->alterInfo($module_handler, 'block');
$this->setCacheBackend($cache_backend, $language_manager, 'block_plugins');
}
}
......@@ -7,25 +7,29 @@
namespace Drupal\system\Plugin;
use Drupal\Component\Plugin\Factory\DefaultFactory;
use Drupal\Component\Plugin\PluginManagerBase;
use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Language\LanguageManager;
use Drupal\Core\Plugin\DefaultPluginManager;
/**
* Manages toolkit plugins.
*/
class ImageToolkitManager extends PluginManagerBase {
class ImageToolkitManager extends DefaultPluginManager {
/**
* Constructs the ImageToolkitManager object.
*
* @param \Traversable $namespaces
* An object that implements \Traversable which contains the root paths
* keyed by the corresponding namespace to look for plugin implementations,
* keyed by the corresponding namespace to look for plugin implementations.
* @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
* Cache backend instance to use.
* @param \Drupal\Core\Language\LanguageManager $language_manager
* The language manager.
*/
public function __construct(\Traversable $namespaces) {
$this->discovery = new AnnotatedClassDiscovery('ImageToolkit', $namespaces);
$this->factory = new DefaultFactory($this->discovery);
public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, LanguageManager $language_manager) {
parent::__construct('ImageToolkit', $namespaces);
$this->setCacheBackend($cache_backend, $language_manager, 'image_toolkit');
}
/**
......
......@@ -215,7 +215,7 @@ function testManipulations() {
);
}
$manager = new ImageToolkitManager($this->container->get('container.namespaces'));
$manager = new ImageToolkitManager($this->container->get('container.namespaces'), $this->container->get('cache.cache'), $this->container->get('language_manager'));
foreach ($files as $file) {
foreach ($operations as $op => $values) {
// Load up a fresh image.
......
......@@ -26,7 +26,7 @@ public static function getInfo() {
* available toolkits.
*/
function testGetAvailableToolkits() {
$manager = new ImageToolkitManager($this->container->get('container.namespaces'));
$manager = new ImageToolkitManager($this->container->get('container.namespaces'), $this->container->get('cache.cache'), $this->container->get('language_manager'));
$toolkits = $manager->getAvailableToolkits();
$this->assertTrue(isset($toolkits['test']), 'The working toolkit was returned.');
$this->assertFalse(isset($toolkits['broken']), 'The toolkit marked unavailable was not returned');
......
......@@ -31,7 +31,7 @@ function setUp() {
parent::setUp();
// Use the image_test.module's test toolkit.
$manager = new ImageToolkitManager($this->container->get('container.namespaces'));
$manager = new ImageToolkitManager($this->container->get('container.namespaces'), $this->container->get('cache.cache'), $this->container->get('language_manager'));
$this->toolkit = $manager->createInstance('test');
// Pick a file for testing.
......
......@@ -33,7 +33,7 @@ public function getFormID() {
* Constructs a \Drupal\condition_test\FormController object.
*/
public function __construct() {
$manager = new ConditionManager(\Drupal::service('container.namespaces'));
$manager = new ConditionManager(\Drupal::service('container.namespaces'), \Drupal::cache('cache'), \Drupal::service('language_manager'), \Drupal::moduleHandler());
$this->condition = $manager->createInstance('node_type');
}
......
......@@ -7,15 +7,14 @@
namespace Drupal\plugin_test\Plugin;
use Drupal\Component\Plugin\PluginManagerBase;
use Drupal\Component\Plugin\Discovery\StaticDiscovery;
use Drupal\Component\Plugin\Discovery\ProcessDecorator;
use Drupal\Component\Plugin\Factory\DefaultFactory;
use Drupal\Core\Plugin\DefaultPluginManager;
/**
* Defines a plugin manager used by Plugin API unit tests.
*/
class DefaultsTestPluginManager extends PluginManagerBase {
class DefaultsTestPluginManager extends DefaultPluginManager {
public function __construct() {
// Create the object that can be used to return definitions for all the
......@@ -23,8 +22,7 @@ public function __construct() {
// discovery implementation, but StaticDiscovery lets us add some simple
// mock plugins for unit testing.
$this->discovery = new StaticDiscovery();
$this->discovery = new ProcessDecorator($this->discovery, array($this, 'ProcessDefinition'));
$this->factory = new DefaultFactory($this->discovery);
$this->factory = new DefaultFactory($this);
// Specify default values.
$this->defaults = array(
......
<?php
/**
* @file
* Contains \Drupal\Core\Plugin\DefaultPluginManagerTest.
*/
namespace Drupal\Tests\Core\Plugin;
use Drupal\Core\Language\Language;
use Drupal\Tests\UnitTestCase;
/**
* Tests the DefaultPluginManager.
*
* @group Plugin
*/
class DefaultPluginManagerTest extends UnitTestCase {
/**
* The expected plugin definitions.
*
* @var array
*/
protected $expectedDefinitions;
/**
* The namespaces to look for plugin definitions.
*