DefaultPluginManager.php 7.61 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
<?php

/**
 * @file
 * Contains \Drupal\Core\Plugin\DefaultPluginManager
 */

namespace Drupal\Core\Plugin;

use Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface;
11
use Drupal\Core\Cache\Cache;
12
use Drupal\Core\Plugin\Discovery\ContainerDerivativeDiscoveryDecorator;
13 14 15 16 17
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;
18
use Drupal\Core\Language\LanguageManagerInterface;
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
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;

56 57 58 59 60 61 62
  /**
   * An array of cache tags to use for the cached definitions.
   *
   * @var array
   */
  protected $cacheTags = array();

63 64 65 66 67 68 69 70
  /**
   * Name of the alter hook if one should be invoked.
   *
   * @var string
   */
  protected $alterHook;

  /**
71 72
   * The subdirectory within a namespace to look for plugins, or FALSE if the
   * plugins are in the top level of the namespace.
73
   *
74
   * @var string|bool
75 76 77 78 79 80 81 82 83 84 85 86 87
   */
  protected $subdir;

  /**
   * The module handler to invoke the alter hook.
   *
   * @var \Drupal\Core\Extension\ModuleHandlerInterface
   */
  protected $moduleHandler;

  /**
   * The language manager.
   *
88
   * @var \Drupal\Core\Language\LanguageManagerInterface
89 90 91 92 93 94
   */
  protected $languageManager;

  /**
   * Creates the discovery object.
   *
95 96
   * @param string|bool $subdir
   *   The plugin's subdirectory, for example Plugin/views/filter.
97 98
   * @param \Traversable $namespaces
   *   An object that implements \Traversable which contains the root paths
99
   *   keyed by the corresponding namespace to look for plugin implementations.
100 101 102 103
   * @param string $plugin_definition_annotation_name
   *   (optional) The name of the annotation that contains the plugin definition.
   *   Defaults to 'Drupal\Component\Annotation\Plugin'.
   */
104
  public function __construct($subdir, \Traversable $namespaces, $plugin_definition_annotation_name = 'Drupal\Component\Annotation\Plugin') {
105
    $this->subdir = $subdir;
106
    $this->discovery = new AnnotatedClassDiscovery($subdir, $namespaces, $plugin_definition_annotation_name);
107
    $this->discovery = new ContainerDerivativeDiscoveryDecorator($this->discovery);
108 109 110 111 112 113 114 115 116 117 118
    $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.
119
   * @param \Drupal\Core\Language\LanguageManagerInterface
120 121 122 123
   *   The language manager.
   * @param string $cache_key_prefix
   *   Cache key prefix to use, the language code will be appended
   *   automatically.
124
   * @param array $cache_tags
125 126 127 128 129 130 131
   *   (optional) When providing a list of cache tags, the cached plugin
   *   definitions are tagged with the provided cache tags. These cache tags can
   *   then be used to clear the corresponding cached plugin definitions. Note
   *   that this should be used with care! For clearing all cached plugin
   *   definitions of a plugin manager, call that plugin manager's
   *   clearCachedDefinitions() method. Only use cache tags when cached plugin
   *   definitions should be cleared along with other, related cache entries.
132
   */
133
  public function setCacheBackend(CacheBackendInterface $cache_backend, LanguageManagerInterface $language_manager, $cache_key_prefix, array $cache_tags = array()) {
134 135 136
    $this->languageManager = $language_manager;
    $this->cacheBackend = $cache_backend;
    $this->cacheKeyPrefix = $cache_key_prefix;
137
    $this->cacheKey = $cache_key_prefix . ':' . $language_manager->getCurrentLanguage()->id;
138
    $this->cacheTags = $cache_tags;
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
  }

  /**
   * 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) {
186 187
      if ($this->cacheTags) {
        // Use the cache tags to clear the cache.
188
        Cache::deleteTags($this->cacheTags);
189
      }
190
      elseif ($this->languageManager) {
191
        $cache_keys = array();
192 193
        foreach ($this->languageManager->getLanguages() as $langcode => $language) {
          $cache_keys[] = $this->cacheKeyPrefix . ':' . $langcode;
194 195
        }
        $this->cacheBackend->deleteMultiple($cache_keys);
196
      }
197 198 199
      else {
        $this->cacheBackend->delete($this->cacheKey);
      }
200 201 202 203 204 205 206
    }
    $this->definitions = NULL;
  }

  /**
   * Returns the cached plugin definitions of the decorated discovery class.
   *
207
   * @return array|null
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
   *   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) {
228
      $this->cacheBackend->set($this->cacheKey, $definitions, CacheBackendInterface::CACHE_PERMANENT, $this->cacheTags);
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
    }
    $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;
  }

}