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. * The name of the annotation that contains the plugin definition.
  78. *
  79. * @var string
  80. */
  81. protected $pluginDefinitionAnnotationName;
  82. /**
  83. * The interface each plugin should implement.
  84. *
  85. * @var string|null
  86. */
  87. protected $pluginInterface;
  88. /**
  89. * An object that implements \Traversable which contains the root paths
  90. * keyed by the corresponding namespace to look for plugin implementations.
  91. *
  92. * @var \Traversable
  93. */
  94. protected $namespaces;
  95. /**
  96. * Creates the discovery object.
  97. *
  98. * @param string|bool $subdir
  99. * The plugin's subdirectory, for example Plugin/views/filter.
  100. * @param \Traversable $namespaces
  101. * An object that implements \Traversable which contains the root paths
  102. * keyed by the corresponding namespace to look for plugin implementations.
  103. * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
  104. * The module handler.
  105. * @param string|null $plugin_interface
  106. * (optional) The interface each plugin should implement.
  107. * @param string $plugin_definition_annotation_name
  108. * (optional) The name of the annotation that contains the plugin definition.
  109. * Defaults to 'Drupal\Component\Annotation\Plugin'.
  110. */
  111. public function __construct($subdir, \Traversable $namespaces, ModuleHandlerInterface $module_handler, $plugin_interface = NULL, $plugin_definition_annotation_name = 'Drupal\Component\Annotation\Plugin') {
  112. $this->subdir = $subdir;
  113. $this->namespaces = $namespaces;
  114. $this->pluginDefinitionAnnotationName = $plugin_definition_annotation_name;
  115. $this->pluginInterface = $plugin_interface;
  116. $this->moduleHandler = $module_handler;
  117. }
  118. /**
  119. * Initialize the cache backend.
  120. *
  121. * Plugin definitions are cached using the provided cache backend. The
  122. * interface language is added as a suffix to the cache key.
  123. *
  124. * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
  125. * Cache backend instance to use.
  126. * @param string $cache_key
  127. * Cache key prefix to use, the language code will be appended
  128. * automatically.
  129. * @param array $cache_tags
  130. * (optional) When providing a list of cache tags, the cached plugin
  131. * definitions are tagged with the provided cache tags. These cache tags can
  132. * then be used to clear the corresponding cached plugin definitions. Note
  133. * that this should be used with care! For clearing all cached plugin
  134. * definitions of a plugin manager, call that plugin manager's
  135. * clearCachedDefinitions() method. Only use cache tags when cached plugin
  136. * definitions should be cleared along with other, related cache entries.
  137. */
  138. public function setCacheBackend(CacheBackendInterface $cache_backend, $cache_key, array $cache_tags = array()) {
  139. Cache::validateTags($cache_tags);
  140. $this->cacheBackend = $cache_backend;
  141. $this->cacheKey = $cache_key;
  142. $this->cacheTags = $cache_tags;
  143. }
  144. /**
  145. * Initializes the alter hook.
  146. *
  147. * @param string $alter_hook
  148. * Name of the alter hook; for example, to invoke
  149. * hook_mymodule_data_alter() pass in "mymodule_data".
  150. */
  151. protected function alterInfo($alter_hook) {
  152. $this->alterHook = $alter_hook;
  153. }
  154. /**
  155. * {@inheritdoc}
  156. */
  157. public function getDefinitions() {
  158. $definitions = $this->getCachedDefinitions();
  159. if (!isset($definitions)) {
  160. $definitions = $this->findDefinitions();
  161. $this->setCachedDefinitions($definitions);
  162. }
  163. return $definitions;
  164. }
  165. /**
  166. * {@inheritdoc}
  167. */
  168. public function clearCachedDefinitions() {
  169. if ($this->cacheBackend) {
  170. if ($this->cacheTags) {
  171. // Use the cache tags to clear the cache.
  172. Cache::invalidateTags($this->cacheTags);
  173. }
  174. else {
  175. $this->cacheBackend->delete($this->cacheKey);
  176. }
  177. }
  178. $this->definitions = NULL;
  179. }
  180. /**
  181. * Returns the cached plugin definitions of the decorated discovery class.
  182. *
  183. * @return array|null
  184. * On success this will return an array of plugin definitions. On failure
  185. * this should return NULL, indicating to other methods that this has not
  186. * yet been defined. Success with no values should return as an empty array
  187. * and would actually be returned by the getDefinitions() method.
  188. */
  189. protected function getCachedDefinitions() {
  190. if (!isset($this->definitions) && $cache = $this->cacheGet($this->cacheKey)) {
  191. $this->definitions = $cache->data;
  192. }
  193. return $this->definitions;
  194. }
  195. /**
  196. * Sets a cache of plugin definitions for the decorated discovery class.
  197. *
  198. * @param array $definitions
  199. * List of definitions to store in cache.
  200. */
  201. protected function setCachedDefinitions($definitions) {
  202. $this->cacheSet($this->cacheKey, $definitions, Cache::PERMANENT, $this->cacheTags);
  203. $this->definitions = $definitions;
  204. }
  205. /**
  206. * {@inheritdoc}
  207. */
  208. public function useCaches($use_caches = FALSE) {
  209. $this->useCaches = $use_caches;
  210. if (!$use_caches) {
  211. $this->definitions = NULL;
  212. }
  213. }
  214. /**
  215. * Fetches from the cache backend, respecting the use caches flag.
  216. *
  217. * @see \Drupal\Core\Cache\CacheBackendInterface::get()
  218. */
  219. protected function cacheGet($cid) {
  220. if ($this->useCaches && $this->cacheBackend) {
  221. return $this->cacheBackend->get($cid);
  222. }
  223. return FALSE;
  224. }
  225. /**
  226. * Stores data in the persistent cache, respecting the use caches flag.
  227. *
  228. * @see \Drupal\Core\Cache\CacheBackendInterface::set()
  229. */
  230. protected function cacheSet($cid, $data, $expire = Cache::PERMANENT, array $tags = array()) {
  231. if ($this->cacheBackend && $this->useCaches) {
  232. $this->cacheBackend->set($cid, $data, $expire, $tags);
  233. }
  234. }
  235. /**
  236. * Performs extra processing on plugin definitions.
  237. *
  238. * By default we add defaults for the type to the definition. If a type has
  239. * additional processing logic they can do that by replacing or extending the
  240. * method.
  241. */
  242. public function processDefinition(&$definition, $plugin_id) {
  243. if (!empty($this->defaults) && is_array($this->defaults)) {
  244. $definition = NestedArray::mergeDeep($this->defaults, $definition);
  245. }
  246. }
  247. /**
  248. * {@inheritdoc}
  249. */
  250. protected function getDiscovery() {
  251. if (!$this->discovery) {
  252. $discovery = new AnnotatedClassDiscovery($this->subdir, $this->namespaces, $this->pluginDefinitionAnnotationName);
  253. $this->discovery = new ContainerDerivativeDiscoveryDecorator($discovery);
  254. }
  255. return $this->discovery;
  256. }
  257. /**
  258. * {@inheritdoc}
  259. */
  260. protected function getFactory() {
  261. if (!$this->factory) {
  262. $this->factory = new ContainerFactory($this, $this->pluginInterface);
  263. }
  264. return $this->factory;
  265. }
  266. /**
  267. * Finds plugin definitions.
  268. *
  269. * @return array
  270. * List of definitions to store in cache.
  271. */
  272. protected function findDefinitions() {
  273. $definitions = $this->getDiscovery()->getDefinitions();
  274. foreach ($definitions as $plugin_id => &$definition) {
  275. $this->processDefinition($definition, $plugin_id);
  276. }
  277. $this->alterDefinitions($definitions);
  278. // If this plugin was provided by a module that does not exist, remove the
  279. // plugin definition.
  280. foreach ($definitions as $plugin_id => $plugin_definition) {
  281. // If the plugin definition is an object, attempt to convert it to an
  282. // array, if that is not possible, skip further processing.
  283. if (is_object($plugin_definition) && !($plugin_definition = (array) $plugin_definition)) {
  284. continue;
  285. }
  286. if (isset($plugin_definition['provider']) && !in_array($plugin_definition['provider'], array('core', 'component')) && !$this->providerExists($plugin_definition['provider'])) {
  287. unset($definitions[$plugin_id]);
  288. }
  289. }
  290. return $definitions;
  291. }
  292. /**
  293. * Invokes the hook to alter the definitions if the alter hook is set.
  294. *
  295. * @param $definitions
  296. * The discovered plugin defintions.
  297. */
  298. protected function alterDefinitions(&$definitions) {
  299. if ($this->alterHook) {
  300. $this->moduleHandler->alter($this->alterHook, $definitions);
  301. }
  302. }
  303. /**
  304. * Determines if the provider of a definition exists.
  305. *
  306. * @return bool
  307. * TRUE if provider exists, FALSE otherwise.
  308. */
  309. protected function providerExists($provider) {
  310. return $this->moduleHandler->moduleExists($provider);
  311. }
  312. }

Classes

Namesort descending Description
DefaultPluginManager Base class for plugin managers.