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

Classes

Namesort descending Description
DefaultPluginManager Base class for plugin managers.