Created
May 1, 2014 12:05
-
-
Save damiankloip/11450184 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/core/core.services.yml b/core/core.services.yml | |
index 19b0b72..ddba8e8 100644 | |
--- a/core/core.services.yml | |
+++ b/core/core.services.yml | |
@@ -795,7 +795,9 @@ services: | |
class: Drupal\Core\Asset\AssetDumper | |
library.discovery: | |
class: Drupal\Core\Asset\LibraryDiscovery | |
- arguments: ['@cache.discovery', '@module_handler'] | |
+ arguments: ['@cache.discovery', '@module_handler', '@lock'] | |
+ tags: | |
+ - { name: needs_destruction } | |
info_parser: | |
class: Drupal\Core\Extension\InfoParser | |
element_info: | |
diff --git a/core/lib/Drupal/Core/Asset/LibraryDiscovery.php b/core/lib/Drupal/Core/Asset/LibraryDiscovery.php | |
index 2a25ea3..d28d74c 100644 | |
--- a/core/lib/Drupal/Core/Asset/LibraryDiscovery.php | |
+++ b/core/lib/Drupal/Core/Asset/LibraryDiscovery.php | |
@@ -7,19 +7,15 @@ | |
namespace Drupal\Core\Asset; | |
-use Drupal\Component\Serialization\Yaml; | |
-use Drupal\Component\Serialization\Exception\InvalidDataTypeException; | |
-use Drupal\Core\Asset\Exception\IncompleteLibraryDefinitionException; | |
-use Drupal\Core\Asset\Exception\InvalidLibraryFileException; | |
-use Drupal\Core\Cache\Cache; | |
use Drupal\Core\Cache\CacheBackendInterface; | |
+use Drupal\Core\DestructableInterface; | |
use Drupal\Core\Extension\ModuleHandlerInterface; | |
-use Drupal\Core\Extension\ThemeHandlerInterface; | |
+use Drupal\Core\Lock\LockBackendInterface; | |
/** | |
* Discovers available asset libraries in Drupal. | |
*/ | |
-class LibraryDiscovery implements LibraryDiscoveryInterface { | |
+class LibraryDiscovery implements LibraryDiscoveryInterface, DestructableInterface { | |
/** | |
* Stores the library information keyed by extension. | |
@@ -43,6 +39,13 @@ class LibraryDiscovery implements LibraryDiscoveryInterface { | |
protected $moduleHandler; | |
/** | |
+ * The lock backend. | |
+ * | |
+ * @var \Drupal\Core\Lock\LockBackendInterface | |
+ */ | |
+ protected $lock; | |
+ | |
+ /** | |
* Constructs a new LibraryDiscovery instance. | |
* | |
* @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend | |
@@ -50,263 +53,34 @@ class LibraryDiscovery implements LibraryDiscoveryInterface { | |
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler | |
* The module handler. | |
*/ | |
- public function __construct(CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) { | |
+ public function __construct(CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, LockBackendInterface $lock_backend) { | |
$this->cache = $cache_backend; | |
$this->moduleHandler = $module_handler; | |
+ $this->lock = $lock_backend; | |
+ $this->collector = new LibraryDiscoveryCollector($cache_backend, $lock_backend, $module_handler); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function getLibrariesByExtension($extension) { | |
- $this->ensureLibraryInformation($extension); | |
- return $this->libraries[$extension]; | |
+ return $this->collector->get($extension); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function getLibraryByName($extension, $name) { | |
- $this->ensureLibraryInformation($extension); | |
- return isset($this->libraries[$extension][$name]) ? $this->libraries[$extension][$name] : FALSE; | |
- } | |
- | |
- /** | |
- * Ensures that the libraries property is filled. | |
- * | |
- * @param string $extension | |
- * The name of the extension that registered a library. | |
- */ | |
- protected function ensureLibraryInformation($extension) { | |
- $this->getCache($extension); | |
- if (!isset($this->libraries[$extension])) { | |
- if ($information = $this->buildLibrariesByExtension($extension)) { | |
- $this->libraries[$extension] = $information; | |
- } | |
- else { | |
- $this->libraries[$extension] = FALSE; | |
- } | |
- $this->setCache($extension, $this->libraries[$extension]); | |
- } | |
- } | |
- | |
- /** | |
- * Fills up the libraries property from cache, if available. | |
- * | |
- * @param string $extension | |
- * The name of the extension that registered a library. | |
- */ | |
- protected function getCache($extension) { | |
- if (!isset($this->libraries[$extension])) { | |
- if ($cache = $this->cache->get('library:info:' . $extension)) { | |
- $this->libraries[$extension] = $cache->data; | |
- } | |
- } | |
- } | |
- | |
- /** | |
- * Sets the library information into a cache entry. | |
- * | |
- * @param string $extension | |
- * The name of the extension that registered a library. | |
- * | |
- * @param bool|array $information | |
- * All library definitions of the passed extension or FALSE if no | |
- * information is available. | |
- */ | |
- protected function setCache($extension, $information) { | |
- $this->cache->set('library:info:' . $extension, $information, Cache::PERMANENT, array( | |
- 'extension' => array(TRUE, $extension), | |
- 'library_info' => array(TRUE), | |
- )); | |
- } | |
- | |
- /** | |
- * Parses and builds up all the libraries information of an extension. | |
- * | |
- * @param string $extension | |
- * The name of the extension that registered a library. | |
- * | |
- * @return array | |
- * All library definitions of the passed extension. | |
- * | |
- * @throws \Drupal\Core\Asset\Exception\IncompleteLibraryDefinitionException | |
- * Thrown when a library has no js/css/setting. | |
- * @throws \UnexpectedValueException | |
- * Thrown when a js file defines a positive weight. | |
- */ | |
- protected function buildLibrariesByExtension($extension) { | |
- $this->libraries[$extension] = array(); | |
- if ($extension === 'core') { | |
- $path = 'core'; | |
- $extension_type = 'core'; | |
- } | |
- else { | |
- if ($this->moduleHandler->moduleExists($extension)) { | |
- $extension_type = 'module'; | |
- } | |
- else { | |
- $extension_type = 'theme'; | |
- } | |
- $path = $this->drupalGetPath($extension_type, $extension); | |
- } | |
- $library_file = $path . '/' . $extension . '.libraries.yml'; | |
- | |
- if ($library_file && file_exists(DRUPAL_ROOT . '/' . $library_file)) { | |
- $this->libraries[$extension] = array(); | |
- $this->parseLibraryInfo($extension, $library_file); | |
- } | |
- | |
- foreach ($this->libraries[$extension] as $id => &$library) { | |
- if (!isset($library['js']) && !isset($library['css']) && !isset($library['settings'])) { | |
- throw new IncompleteLibraryDefinitionException(sprintf("Incomplete library definition for '%s' in %s", $id, $library_file)); | |
- } | |
- $library += array('dependencies' => array(), 'js' => array(), 'css' => array()); | |
- | |
- if (isset($library['version'])) { | |
- // @todo Retrieve version of a non-core extension. | |
- if ($library['version'] === 'VERSION') { | |
- $library['version'] = \Drupal::VERSION; | |
- } | |
- // Remove 'v' prefix from external library versions. | |
- elseif ($library['version'][0] === 'v') { | |
- $library['version'] = substr($library['version'], 1); | |
- } | |
- } | |
- | |
- foreach (array('js', 'css') as $type) { | |
- // Prepare (flatten) the SMACSS-categorized definitions. | |
- // @todo After Asset(ic) changes, retain the definitions as-is and | |
- // properly resolve dependencies for all (css) libraries per category, | |
- // and only once prior to rendering out an HTML page. | |
- if ($type == 'css' && !empty($library[$type])) { | |
- foreach ($library[$type] as $category => $files) { | |
- foreach ($files as $source => $options) { | |
- if (!isset($options['weight'])) { | |
- $options['weight'] = 0; | |
- } | |
- // Apply the corresponding weight defined by CSS_* constants. | |
- $options['weight'] += constant('CSS_' . strtoupper($category)); | |
- $library[$type][$source] = $options; | |
- } | |
- unset($library[$type][$category]); | |
- } | |
- } | |
- foreach ($library[$type] as $source => $options) { | |
- unset($library[$type][$source]); | |
- // Allow to omit the options hashmap in YAML declarations. | |
- if (!is_array($options)) { | |
- $options = array(); | |
- } | |
- if ($type == 'js' && isset($options['weight']) && $options['weight'] > 0) { | |
- throw new \UnexpectedValueException("The $extension/$id library defines a positive weight for '$source'. Only negative weights are allowed (but should be avoided). Instead of a positive weight, specify accurate dependencies for this library."); | |
- } | |
- // Unconditionally apply default groups for the defined asset files. | |
- // The library system is a dependency management system. Each library | |
- // properly specifies its dependencies instead of relying on a custom | |
- // processing order. | |
- if ($type == 'js') { | |
- $options['group'] = JS_LIBRARY; | |
- } | |
- elseif ($type == 'css') { | |
- $options['group'] = $extension_type == 'theme' ? CSS_AGGREGATE_THEME : CSS_AGGREGATE_DEFAULT; | |
- } | |
- // By default, all library assets are files. | |
- if (!isset($options['type'])) { | |
- $options['type'] = 'file'; | |
- } | |
- if ($options['type'] == 'external') { | |
- $options['data'] = $source; | |
- } | |
- // Determine the file asset URI. | |
- else { | |
- if ($source[0] === '/') { | |
- // An absolute path maps to DRUPAL_ROOT / base_path(). | |
- if ($source[1] !== '/') { | |
- $options['data'] = substr($source, 1); | |
- } | |
- // A protocol-free URI (e.g., //cdn.com/example.js) is external. | |
- else { | |
- $options['type'] = 'external'; | |
- $options['data'] = $source; | |
- } | |
- } | |
- // A stream wrapper URI (e.g., public://generated_js/example.js). | |
- elseif ($this->fileValidUri($source)) { | |
- $options['data'] = $source; | |
- } | |
- // By default, file paths are relative to the registering extension. | |
- else { | |
- $options['data'] = $path . '/' . $source; | |
- } | |
- } | |
- | |
- if (!isset($library['version'])) { | |
- // @todo Get the information from the extension. | |
- $options['version'] = -1; | |
- } | |
- else { | |
- $options['version'] = $library['version']; | |
- } | |
- | |
- $library[$type][] = $options; | |
- } | |
- } | |
- | |
- // @todo Introduce drupal_add_settings(). | |
- if (isset($library['settings'])) { | |
- $library['js'][] = array( | |
- 'type' => 'setting', | |
- 'data' => $library['settings'], | |
- ); | |
- unset($library['settings']); | |
- } | |
- // @todo Convert all uses of #attached[library][]=array('provider','name') | |
- // into #attached[library][]='provider/name' and remove this. | |
- foreach ($library['dependencies'] as $i => $dependency) { | |
- $library['dependencies'][$i] = $dependency; | |
- } | |
- } | |
- return $this->libraries[$extension]; | |
- } | |
- | |
- /** | |
- * Wraps drupal_get_path(). | |
- */ | |
- protected function drupalGetPath($type, $name) { | |
- return drupal_get_path($type, $name); | |
+ $extension = $this->getLibrariesByExtension($extension); | |
+ return isset($extension[$name]) ? $extension[$name] : FALSE; | |
} | |
/** | |
- * Wraps file_valid_uri(). | |
+ * Performs destruct operations. | |
*/ | |
- protected function fileValidUri($source) { | |
- return file_valid_uri($source); | |
+ public function destruct() { | |
+ $this->collector->destruct(); | |
} | |
- /** | |
- * Parses a given library file and allows module to alter it. | |
- * | |
- * This method sets the parsed information onto the library property. | |
- * | |
- * @param string $extension | |
- * The name of the extension that registered a library. | |
- * @param string $library_file | |
- * The relative filename to the DRUPAL_ROOT of the wanted library file. | |
- * | |
- * @throws \Drupal\Core\Asset\Exception\InvalidLibraryFileException | |
- * Thrown when a parser exception got thrown. | |
- */ | |
- protected function parseLibraryInfo($extension, $library_file) { | |
- try { | |
- $this->libraries[$extension] = Yaml::decode(file_get_contents(DRUPAL_ROOT . '/' . $library_file)); | |
- } | |
- catch (InvalidDataTypeException $e) { | |
- // Rethrow a more helpful exception to provide context. | |
- throw new InvalidLibraryFileException(sprintf('Invalid library definition in %s: %s', $library_file, $e->getMessage()), 0, $e); | |
- } | |
- // Allow modules to alter the module's registered libraries. | |
- $this->moduleHandler->alter('library_info', $this->libraries[$extension], $extension); | |
- } | |
} | |
diff --git a/core/lib/Drupal/Core/Asset/LibraryDiscovery.php b/core/lib/Drupal/Core/Asset/LibraryDiscoveryCollector.php | |
similarity index 70% | |
copy from core/lib/Drupal/Core/Asset/LibraryDiscovery.php | |
copy to core/lib/Drupal/Core/Asset/LibraryDiscoveryCollector.php | |
index 2a25ea3..e38217a 100644 | |
--- a/core/lib/Drupal/Core/Asset/LibraryDiscovery.php | |
+++ b/core/lib/Drupal/Core/Asset/LibraryDiscoveryCollector.php | |
@@ -2,38 +2,31 @@ | |
/** | |
* @file | |
- * Contains \Drupal\Core\Asset\LibraryDiscovery. | |
+ * Contains \Drupal\Core\Asset\LibraryDiscoveryCollector. | |
*/ | |
namespace Drupal\Core\Asset; | |
-use Drupal\Component\Serialization\Yaml; | |
-use Drupal\Component\Serialization\Exception\InvalidDataTypeException; | |
use Drupal\Core\Asset\Exception\IncompleteLibraryDefinitionException; | |
use Drupal\Core\Asset\Exception\InvalidLibraryFileException; | |
-use Drupal\Core\Cache\Cache; | |
+use Drupal\Core\Cache\CacheCollector; | |
use Drupal\Core\Cache\CacheBackendInterface; | |
use Drupal\Core\Extension\ModuleHandlerInterface; | |
-use Drupal\Core\Extension\ThemeHandlerInterface; | |
+use Drupal\Core\Lock\LockBackendInterface; | |
+use Drupal\Component\Serialization\Exception\InvalidDataTypeException; | |
+use Drupal\Component\Serialization\Yaml; | |
/** | |
- * Discovers available asset libraries in Drupal. | |
+ * Class LibraryDiscoveryCollector. | |
*/ | |
-class LibraryDiscovery implements LibraryDiscoveryInterface { | |
+class LibraryDiscoveryCollector extends CacheCollector { | |
/** | |
- * Stores the library information keyed by extension. | |
+ * The cache key. | |
* | |
- * @var array | |
+ * @var string | |
*/ | |
- protected $libraries; | |
- | |
- /** | |
- * The cache backend. | |
- * | |
- * @var \Drupal\Core\Cache\CacheBackendInterface | |
- */ | |
- protected $cache; | |
+ protected $cacheKey = 'library_info'; | |
/** | |
* The module handler. | |
@@ -43,82 +36,31 @@ class LibraryDiscovery implements LibraryDiscoveryInterface { | |
protected $moduleHandler; | |
/** | |
- * Constructs a new LibraryDiscovery instance. | |
+ * Constructs a CacheCollector object. | |
* | |
- * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend | |
+ * @param string $cid | |
+ * The cid for the array being cached. | |
+ * @param \Drupal\Core\Cache\CacheBackendInterface $cache | |
* The cache backend. | |
- * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler | |
- * The module handler. | |
+ * @param \Drupal\Core\Lock\LockBackendInterface $lock | |
+ * The lock backend. | |
+ * @param array $tags | |
+ * (optional) The tags to specify for the cache item. | |
*/ | |
- public function __construct(CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) { | |
- $this->cache = $cache_backend; | |
+ public function __construct(CacheBackendInterface $cache, LockBackendInterface $lock, ModuleHandlerInterface $module_handler) { | |
+ parent::__construct($this->cacheKey, $cache, $lock, array($this->cacheKey => array(TRUE))); | |
+ | |
$this->moduleHandler = $module_handler; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
- public function getLibrariesByExtension($extension) { | |
- $this->ensureLibraryInformation($extension); | |
- return $this->libraries[$extension]; | |
- } | |
+ protected function resolveCacheMiss($key) { | |
+ $extension = $this->buildLibrariesByExtension($key); | |
+ $this->persist($key); | |
- /** | |
- * {@inheritdoc} | |
- */ | |
- public function getLibraryByName($extension, $name) { | |
- $this->ensureLibraryInformation($extension); | |
- return isset($this->libraries[$extension][$name]) ? $this->libraries[$extension][$name] : FALSE; | |
- } | |
- | |
- /** | |
- * Ensures that the libraries property is filled. | |
- * | |
- * @param string $extension | |
- * The name of the extension that registered a library. | |
- */ | |
- protected function ensureLibraryInformation($extension) { | |
- $this->getCache($extension); | |
- if (!isset($this->libraries[$extension])) { | |
- if ($information = $this->buildLibrariesByExtension($extension)) { | |
- $this->libraries[$extension] = $information; | |
- } | |
- else { | |
- $this->libraries[$extension] = FALSE; | |
- } | |
- $this->setCache($extension, $this->libraries[$extension]); | |
- } | |
- } | |
- | |
- /** | |
- * Fills up the libraries property from cache, if available. | |
- * | |
- * @param string $extension | |
- * The name of the extension that registered a library. | |
- */ | |
- protected function getCache($extension) { | |
- if (!isset($this->libraries[$extension])) { | |
- if ($cache = $this->cache->get('library:info:' . $extension)) { | |
- $this->libraries[$extension] = $cache->data; | |
- } | |
- } | |
- } | |
- | |
- /** | |
- * Sets the library information into a cache entry. | |
- * | |
- * @param string $extension | |
- * The name of the extension that registered a library. | |
- * | |
- * @param bool|array $information | |
- * All library definitions of the passed extension or FALSE if no | |
- * information is available. | |
- */ | |
- protected function setCache($extension, $information) { | |
- $this->cache->set('library:info:' . $extension, $information, Cache::PERMANENT, array( | |
- 'extension' => array(TRUE, $extension), | |
- 'library_info' => array(TRUE), | |
- )); | |
+ return $extension; | |
} | |
/** | |
@@ -136,7 +78,7 @@ protected function setCache($extension, $information) { | |
* Thrown when a js file defines a positive weight. | |
*/ | |
protected function buildLibrariesByExtension($extension) { | |
- $this->libraries[$extension] = array(); | |
+ $this->storage[$extension] = array(); | |
if ($extension === 'core') { | |
$path = 'core'; | |
$extension_type = 'core'; | |
@@ -153,11 +95,11 @@ protected function buildLibrariesByExtension($extension) { | |
$library_file = $path . '/' . $extension . '.libraries.yml'; | |
if ($library_file && file_exists(DRUPAL_ROOT . '/' . $library_file)) { | |
- $this->libraries[$extension] = array(); | |
+ $this->storage[$extension] = array(); | |
$this->parseLibraryInfo($extension, $library_file); | |
} | |
- foreach ($this->libraries[$extension] as $id => &$library) { | |
+ foreach ($this->storage[$extension] as $id => &$library) { | |
if (!isset($library['js']) && !isset($library['css']) && !isset($library['settings'])) { | |
throw new IncompleteLibraryDefinitionException(sprintf("Incomplete library definition for '%s' in %s", $id, $library_file)); | |
} | |
@@ -267,21 +209,7 @@ protected function buildLibrariesByExtension($extension) { | |
$library['dependencies'][$i] = $dependency; | |
} | |
} | |
- return $this->libraries[$extension]; | |
- } | |
- | |
- /** | |
- * Wraps drupal_get_path(). | |
- */ | |
- protected function drupalGetPath($type, $name) { | |
- return drupal_get_path($type, $name); | |
- } | |
- | |
- /** | |
- * Wraps file_valid_uri(). | |
- */ | |
- protected function fileValidUri($source) { | |
- return file_valid_uri($source); | |
+ return $this->storage[$extension]; | |
} | |
/** | |
@@ -299,14 +227,28 @@ protected function fileValidUri($source) { | |
*/ | |
protected function parseLibraryInfo($extension, $library_file) { | |
try { | |
- $this->libraries[$extension] = Yaml::decode(file_get_contents(DRUPAL_ROOT . '/' . $library_file)); | |
+ $this->storage[$extension] = Yaml::decode(file_get_contents(DRUPAL_ROOT . '/' . $library_file)); | |
} | |
catch (InvalidDataTypeException $e) { | |
// Rethrow a more helpful exception to provide context. | |
throw new InvalidLibraryFileException(sprintf('Invalid library definition in %s: %s', $library_file, $e->getMessage()), 0, $e); | |
} | |
// Allow modules to alter the module's registered libraries. | |
- $this->moduleHandler->alter('library_info', $this->libraries[$extension], $extension); | |
+ $this->moduleHandler->alter('library_info', $this->storage[$extension], $extension); | |
+ } | |
+ | |
+ /** | |
+ * Wraps drupal_get_path(). | |
+ */ | |
+ protected function drupalGetPath($type, $name) { | |
+ return drupal_get_path($type, $name); | |
+ } | |
+ | |
+ /** | |
+ * Wraps file_valid_uri(). | |
+ */ | |
+ protected function fileValidUri($source) { | |
+ return file_valid_uri($source); | |
} | |
} | |
diff --git a/core/tests/Drupal/Tests/Core/Asset/LibraryDiscoveryTest.php b/core/tests/Drupal/Tests/Core/Asset/LibraryDiscoveryTest.php | |
index 230cac6..52f38b5 100644 | |
--- a/core/tests/Drupal/Tests/Core/Asset/LibraryDiscoveryTest.php | |
+++ b/core/tests/Drupal/Tests/Core/Asset/LibraryDiscoveryTest.php | |
@@ -58,11 +58,11 @@ class LibraryDiscoveryTest extends UnitTestCase { | |
protected $moduleHandler; | |
/** | |
- * The mocked theme handler. | |
+ * The mocked lock backend.. | |
* | |
- * @var \Drupal\Core\Extension\ThemeHandlerInterface | |
+ * @var \Drupal\Core\Lock\LockBackendInterface|\PHPUnit_Framework_MockObject_MockObject | |
*/ | |
- protected $themeHandler; | |
+ protected $lock; | |
/** | |
* {@inheritdoc} | |
@@ -81,8 +81,8 @@ public static function getInfo() { | |
protected function setUp() { | |
$this->cache = $this->getMock('Drupal\Core\Cache\CacheBackendInterface'); | |
$this->moduleHandler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface'); | |
- $this->themeHandler = $this->getMock('Drupal\Core\Extension\ThemeHandlerInterface'); | |
- $this->libraryDiscovery = new TestLibraryDiscovery($this->cache, $this->moduleHandler, $this->themeHandler); | |
+ $this->lock = $this->getMock('Drupal\Core\Lock\LockBackendInterface'); | |
+ $this->libraryDiscovery = new TestLibraryDiscovery($this->cache, $this->moduleHandler, $this->lock); | |
} | |
/** |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment