Contains \Drupal\Core\Plugin\DefaultPluginManager.

Namespace

Drupal\Core\Plugin

File

core/lib/Drupal/Core/Plugin/DefaultPluginManager.php
View source
  1. <?php
  2. /**
  3. * @file
  4. * Contains \Drupal\Core\Plugin\DefaultPluginManager.
  5. */
  6. namespace Drupal\Core\Plugin;
  7. use Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface;
  8. use Drupal\Core\Cache\CacheBackendInterface;
  9. use Drupal\Core\Cache\UseCacheBackendTrait;
  10. use Drupal\Component\Plugin\Discovery\DiscoveryCachedTrait;
  11. use Drupal\Core\Plugin\Discovery\ContainerDerivativeDiscoveryDecorator;
  12. use Drupal\Component\Plugin\PluginManagerBase;
  13. use Drupal\Component\Plugin\PluginManagerInterface;
  14. use Drupal\Component\Utility\NestedArray;
  15. use Drupal\Core\Cache\Cache;
  16. use Drupal\Core\Extension\ModuleHandlerInterface;
  17. use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
  18. use Drupal\Core\Plugin\Factory\ContainerFactory;
  19. /**
  20. * Base class for plugin managers.
  21. *
  22. * @ingroup plugin_api
  23. */
  24. class DefaultPluginManager extends PluginManagerBase implements PluginManagerInterface, CachedDiscoveryInterface {
  25. use DiscoveryCachedTrait;
  26. use UseCacheBackendTrait;
  27. /**
  28. * The cache key.
  29. *
  30. * @var string
  31. */
  32. protected $cacheKey;
  33. /**
  34. * An array of cache tags to use for the cached definitions.
  35. *
  36. * @var array
  37. */
  38. protected $cacheTags = array();
  39. /**
  40. * Name of the alter hook if one should be invoked.
  41. *
  42. * @var string
  43. */
  44. protected $alterHook;
  45. /**
  46. * The subdirectory within a namespace to look for plugins, or FALSE if the
  47. * plugins are in the top level of the namespace.
  48. *
  49. * @var string|bool
  50. */
  51. protected $subdir;
  52. /**
  53. * The module handler to invoke the alter hook.
  54. *
  55. * @var \Drupal\Core\Extension\ModuleHandlerInterface
  56. */
  57. protected $moduleHandler;
  58. /**
  59. * A set of defaults to be referenced by $this->processDefinition() if
  60. * additional processing of plugins is necessary or helpful for development
  61. * purposes.
  62. *
  63. * @var array
  64. */
  65. protected $defaults = array();
  66. /**
  67. * The name of the annotation that contains the plugin definition.
  68. *
  69. * @var string
  70. */
  71. protected $pluginDefinitionAnnotationName;
  72. /**
  73. * The interface each plugin should implement.
  74. *
  75. * @var string|null
  76. */
  77. protected $pluginInterface;
  78. /**
  79. * An object that implements \Traversable which contains the root paths
  80. * keyed by the corresponding namespace to look for plugin implementations.
  81. *
  82. * @var \Traversable
  83. */
  84. protected $namespaces;
  85. /**
  86. * Creates the discovery object.
  87. *
  88. * @param string|bool $subdir
  89. * The plugin's subdirectory, for example Plugin/views/filter.
  90. * @param \Traversable $namespaces
  91. * An object that implements \Traversable which contains the root paths
  92. * keyed by the corresponding namespace to look for plugin implementations.
  93. * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
  94. * The module handler.
  95. * @param string|null $plugin_interface
  96. * (optional) The interface each plugin should implement.
  97. * @param string $plugin_definition_annotation_name
  98. * (optional) The name of the annotation that contains the plugin definition.
  99. * Defaults to 'Drupal\Component\Annotation\Plugin'.
  100. */
  101. public function __construct($subdir, \Traversable $namespaces, ModuleHandlerInterface $module_handler, $plugin_interface = NULL, $plugin_definition_annotation_name = 'Drupal\Component\Annotation\Plugin') {
  102. $this->subdir = $subdir;
  103. $this->namespaces = $namespaces;
  104. $this->pluginDefinitionAnnotationName = $plugin_definition_annotation_name;
  105. $this->pluginInterface = $plugin_interface;
  106. $this->moduleHandler = $module_handler;
  107. }
  108. /**
  109. * Initialize the cache backend.
  110. *
  111. * Plugin definitions are cached using the provided cache backend. The
  112. * interface language is added as a suffix to the cache key.
  113. *
  114. * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
  115. * Cache backend instance to use.
  116. * @param string $cache_key
  117. * Cache key prefix to use, the language code will be appended
  118. * automatically.
  119. * @param array $cache_tags
  120. * (optional) When providing a list of cache tags, the cached plugin
  121. * definitions are tagged with the provided cache tags. These cache tags can
  122. * then be used to clear the corresponding cached plugin definitions. Note
  123. * that this should be used with care! For clearing all cached plugin
  124. * definitions of a plugin manager, call that plugin manager's
  125. * clearCachedDefinitions() method. Only use cache tags when cached plugin
  126. * definitions should be cleared along with other, related cache entries.
  127. */
  128. public function setCacheBackend(CacheBackendInterface $cache_backend, $cache_key, array $cache_tags = array()) {
  129. assert('\Drupal\Component\Assertion\Inspector::assertAllStrings($cache_tags)', 'Cache Tags must be strings.');
  130. $this->cacheBackend = $cache_backend;
  131. $this->cacheKey = $cache_key;
  132. $this->cacheTags = $cache_tags;
  133. }
  134. /**
  135. * Initializes the alter hook.
  136. *
  137. * @param string $alter_hook
  138. * Name of the alter hook; for example, to invoke
  139. * hook_mymodule_data_alter() pass in "mymodule_data".
  140. */
  141. protected function alterInfo($alter_hook) {
  142. $this->alterHook = $alter_hook;
  143. }
  144. /**
  145. * {@inheritdoc}
  146. */
  147. public function getDefinitions() {
  148. $definitions = $this->getCachedDefinitions();
  149. if (!isset($definitions)) {
  150. $definitions = $this->findDefinitions();
  151. $this->setCachedDefinitions($definitions);
  152. }
  153. return $definitions;
  154. }
  155. /**
  156. * {@inheritdoc}
  157. */
  158. public function clearCachedDefinitions() {
  159. if ($this->cacheBackend) {
  160. if ($this->cacheTags) {
  161. // Use the cache tags to clear the cache.
  162. Cache::invalidateTags($this->cacheTags);
  163. }
  164. else {
  165. $this->cacheBackend->delete($this->cacheKey);
  166. }
  167. }
  168. $this->definitions = NULL;
  169. }
  170. /**
  171. * Returns the cached plugin definitions of the decorated discovery class.
  172. *
  173. * @return array|null
  174. * On success this will return an array of plugin definitions. On failure
  175. * this should return NULL, indicating to other methods that this has not
  176. * yet been defined. Success with no values should return as an empty array
  177. * and would actually be returned by the getDefinitions() method.
  178. */
  179. protected function getCachedDefinitions() {
  180. if (!isset($this->definitions) && $cache = $this->cacheGet($this->cacheKey)) {
  181. $this->definitions = $cache->data;
  182. }
  183. return $this->definitions;
  184. }
  185. /**
  186. * Sets a cache of plugin definitions for the decorated discovery class.
  187. *
  188. * @param array $definitions
  189. * List of definitions to store in cache.
  190. */
  191. protected function setCachedDefinitions($definitions) {
  192. $this->cacheSet($this->cacheKey, $definitions, Cache::PERMANENT, $this->cacheTags);
  193. $this->definitions = $definitions;
  194. }
  195. /**
  196. * {@inheritdoc}
  197. */
  198. public function useCaches($use_caches = FALSE) {
  199. $this->useCaches = $use_caches;
  200. if (!$use_caches) {
  201. $this->definitions = NULL;
  202. }
  203. }
  204. /**
  205. * Performs extra processing on plugin definitions.
  206. *
  207. * By default we add defaults for the type to the definition. If a type has
  208. * additional processing logic they can do that by replacing or extending the
  209. * method.
  210. */
  211. public function processDefinition(&$definition, $plugin_id) {
  212. if (!empty($this->defaults) && is_array($this->defaults)) {
  213. $definition = NestedArray::mergeDeep($this->defaults, $definition);
  214. }
  215. }
  216. /**
  217. * {@inheritdoc}
  218. */
  219. protected function getDiscovery() {
  220. if (!$this->discovery) {
  221. $discovery = new AnnotatedClassDiscovery($this->subdir, $this->namespaces, $this->pluginDefinitionAnnotationName);
  222. $this->discovery = new ContainerDerivativeDiscoveryDecorator($discovery);
  223. }
  224. return $this->discovery;
  225. }
  226. /**
  227. * {@inheritdoc}
  228. */
  229. protected function getFactory() {
  230. if (!$this->factory) {
  231. $this->factory = new ContainerFactory($this, $this->pluginInterface);
  232. }
  233. return $this->factory;
  234. }
  235. /**
  236. * Finds plugin definitions.
  237. *
  238. * @return array
  239. * List of definitions to store in cache.
  240. */
  241. protected function findDefinitions() {
  242. $definitions = $this->getDiscovery()->getDefinitions();
  243. foreach ($definitions as $plugin_id => &$definition) {
  244. $this->processDefinition($definition, $plugin_id);
  245. }
  246. $this->alterDefinitions($definitions);
  247. // If this plugin was provided by a module that does not exist, remove the
  248. // plugin definition.
  249. foreach ($definitions as $plugin_id => $plugin_definition) {
  250. // If the plugin definition is an object, attempt to convert it to an
  251. // array, if that is not possible, skip further processing.
  252. if (is_object($plugin_definition) && !($plugin_definition = (array) $plugin_definition)) {
  253. continue;
  254. }
  255. if (isset($plugin_definition['provider']) && !in_array($plugin_definition['provider'], array('core', 'component')) && !$this->providerExists($plugin_definition['provider'])) {
  256. unset($definitions[$plugin_id]);
  257. }
  258. }
  259. return $definitions;
  260. }
  261. /**
  262. * Invokes the hook to alter the definitions if the alter hook is set.
  263. *
  264. * @param $definitions
  265. * The discovered plugin definitions.
  266. */
  267. protected function alterDefinitions(&$definitions) {
  268. if ($this->alterHook) {
  269. $this->moduleHandler->alter($this->alterHook, $definitions);
  270. }
  271. }
  272. /**
  273. * Determines if the provider of a definition exists.
  274. *
  275. * @return bool
  276. * TRUE if provider exists, FALSE otherwise.
  277. */
  278. protected function providerExists($provider) {
  279. return $this->moduleHandler->moduleExists($provider);
  280. }
  281. }

Classes

Namesort descending Description
DefaultPluginManager Base class for plugin managers.