diff --git a/core/core.services.yml b/core/core.services.yml index 69e084a3364..d0facb4c4e3 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -819,7 +819,15 @@ services: class: Drupal\Core\Asset\AssetDumper library.discovery: class: Drupal\Core\Asset\LibraryDiscovery - arguments: ['@cache.discovery', '@module_handler'] + arguments: ['@library.discovery.collector'] + library.discovery.collector: + class: Drupal\Core\Asset\LibraryDiscoveryCollector + arguments: ['@cache.discovery', '@lock', '@library.discovery.parser'] + tags: + - { name: needs_destruction } + library.discovery.parser: + class: Drupal\Core\Asset\LibraryDiscoveryParser + arguments: ['@module_handler'] 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 2a25ea38116..b0c3696b28b 100644 --- a/core/lib/Drupal/Core/Asset/LibraryDiscovery.php +++ b/core/lib/Drupal/Core/Asset/LibraryDiscovery.php @@ -7,14 +7,7 @@ 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\Extension\ModuleHandlerInterface; -use Drupal\Core\Extension\ThemeHandlerInterface; +use Drupal\Core\Cache\CacheCollectorInterface; /** * Discovers available asset libraries in Drupal. @@ -22,25 +15,11 @@ use Drupal\Core\Extension\ThemeHandlerInterface; class LibraryDiscovery implements LibraryDiscoveryInterface { /** - * Stores the library information keyed by extension. + * The library discovery cache collector. * - * @var array + * @var \Drupal\Core\Cache\CacheCollectorInterface */ - protected $libraries; - - /** - * The cache backend. - * - * @var \Drupal\Core\Cache\CacheBackendInterface - */ - protected $cache; - - /** - * The module handler. - * - * @var \Drupal\Core\Extension\ModuleHandlerInterface - */ - protected $moduleHandler; + protected $collector; /** * Constructs a new LibraryDiscovery instance. @@ -50,263 +29,23 @@ class LibraryDiscovery implements LibraryDiscoveryInterface { * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler * The module handler. */ - public function __construct(CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) { - $this->cache = $cache_backend; - $this->moduleHandler = $module_handler; + public function __construct(CacheCollectorInterface $library_discovery_collector) { + $this->collector = $library_discovery_collector; } /** * {@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); - } - - /** - * Wraps file_valid_uri(). - */ - protected function fileValidUri($source) { - return file_valid_uri($source); - } - - /** - * 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); + $extension = $this->getLibrariesByExtension($extension); + return isset($extension[$name]) ? $extension[$name] : FALSE; } } diff --git a/core/lib/Drupal/Core/Asset/LibraryDiscoveryCollector.php b/core/lib/Drupal/Core/Asset/LibraryDiscoveryCollector.php new file mode 100644 index 00000000000..e174a17f3a3 --- /dev/null +++ b/core/lib/Drupal/Core/Asset/LibraryDiscoveryCollector.php @@ -0,0 +1,75 @@ +cacheKey, $cache, $lock, array($this->cacheKey => array(TRUE))); + + $this->discoveryParser = $discovery_parser; + } + + /** + * {@inheritdoc} + */ + protected function resolveCacheMiss($key) { + $this->storage[$key] = $this->discoveryParser->buildByExtension($key); + $this->persist($key); + + return $this->storage[$key]; + } + +} diff --git a/core/lib/Drupal/Core/Asset/LibraryDiscoveryParser.php b/core/lib/Drupal/Core/Asset/LibraryDiscoveryParser.php new file mode 100644 index 00000000000..cbe26209030 --- /dev/null +++ b/core/lib/Drupal/Core/Asset/LibraryDiscoveryParser.php @@ -0,0 +1,231 @@ +moduleHandler = $module_handler; + } + + /** + * 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. + */ + public function buildByExtension($extension) { + $libraries = 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)) { + $libraries = $this->parseLibraryInfo($extension, $library_file); + } + + foreach ($libraries 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 $libraries; + } + + /** + * 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. + * + * @return array + * An array of parsed library data. + * + * @throws \Drupal\Core\Asset\Exception\InvalidLibraryFileException + * Thrown when a parser exception got thrown. + */ + protected function parseLibraryInfo($extension, $library_file) { + try { + $libraries = 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', $libraries, $extension); + + return $libraries; + } + + /** + * 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/LibraryDiscoveryCollectorTest.php b/core/tests/Drupal/Tests/Core/Asset/LibraryDiscoveryCollectorTest.php new file mode 100644 index 00000000000..5406648dede --- /dev/null +++ b/core/tests/Drupal/Tests/Core/Asset/LibraryDiscoveryCollectorTest.php @@ -0,0 +1,132 @@ + array( + 'js' => array(), + 'css' => array(), + ), + 'test_2' => array( + 'js' => array(), + 'css' => array(), + ), + ); + + /** + * {@inheritdoc} + */ + public static function getInfo() { + return array( + 'name' => 'Tests \Drupal\Core\Asset\LibraryDiscoveryCollector', + 'description' => '', + 'group' => 'Asset handling', + ); + } + + /** + * {@inheritdoc} + */ + public function setUp() { + $this->cache = $this->getMock('Drupal\Core\Cache\CacheBackendInterface'); + $this->lock = $this->getMock('Drupal\Core\Lock\LockBackendInterface'); + $this->libraryDiscoveryParser = $this->getMockBuilder('Drupal\Core\Asset\LibraryDiscoveryParser') + ->disableOriginalConstructor() + ->getMock(); + + $this->libraryDiscoveryCollector = new LibraryDiscoveryCollector($this->cache, $this->lock, $this->libraryDiscoveryParser); + } + + /** + * Tests the resolve cache miss function. + * + * @covers ::resolveCacheMiss + */ + public function testResolveCacheMiss() { + $this->libraryDiscoveryParser->expects($this->once()) + ->method('buildByExtension') + ->with('test') + ->will($this->returnValue($this->libraryData)); + + $this->assertSame($this->libraryData, $this->libraryDiscoveryCollector->get('test')); + $this->assertSame($this->libraryData, $this->libraryDiscoveryCollector->get('test')); + } + + /** + * Tests the destruct method. + * + * @covers ::destruct + */ + public function testDestruct() { + $this->libraryDiscoveryParser->expects($this->once()) + ->method('buildByExtension') + ->with('test') + ->will($this->returnValue($this->libraryData)); + + $lock_key = 'library_info:Drupal\Core\Cache\CacheCollector'; + + $this->lock->expects($this->once()) + ->method('acquire') + ->with($lock_key) + ->will($this->returnValue(TRUE)); + $this->cache->expects($this->exactly(2)) + ->method('get') + ->with('library_info') + ->will($this->returnValue(FALSE)); + $this->cache->expects($this->once()) + ->method('set') + ->with('library_info', array('test' => $this->libraryData), Cache::PERMANENT, array('library_info' => array(TRUE))); + $this->lock->expects($this->once()) + ->method('release') + ->with($lock_key); + + // This should get data and persist the key. + $this->libraryDiscoveryCollector->get('test'); + $this->libraryDiscoveryCollector->destruct(); + } + +} diff --git a/core/tests/Drupal/Tests/Core/Asset/LibraryDiscoveryTest.php b/core/tests/Drupal/Tests/Core/Asset/LibraryDiscoveryParserTestParser.php similarity index 55% rename from core/tests/Drupal/Tests/Core/Asset/LibraryDiscoveryTest.php rename to core/tests/Drupal/Tests/Core/Asset/LibraryDiscoveryParserTestParser.php index 230cac61dd5..ccf9aa96303 100644 --- a/core/tests/Drupal/Tests/Core/Asset/LibraryDiscoveryTest.php +++ b/core/tests/Drupal/Tests/Core/Asset/LibraryDiscoveryParserTestParser.php @@ -7,8 +7,7 @@ namespace Drupal\Tests\Core\Asset; -use Drupal\Core\Asset\LibraryDiscovery; -use Drupal\Core\Cache\Cache; +use Drupal\Core\Asset\LibraryDiscoveryParser; use Drupal\Tests\UnitTestCase; if (!defined('DRUPAL_ROOT')) { @@ -30,18 +29,18 @@ if (!defined('CSS_AGGREGATE_DEFAULT')) { } /** - * Tests the library discovery. + * Tests the library discovery parser. * - * @coversDefaultClass \Drupal\Core\Asset\LibraryDiscovery + * @coversDefaultClass \Drupal\Core\Asset\LibraryDiscoveryParser */ -class LibraryDiscoveryTest extends UnitTestCase { +class LibraryDiscoveryParserTest extends UnitTestCase { /** * The tested library provider. * - * @var \Drupal\Core\Asset\LibraryDiscovery|\Drupal\Tests\Core\Asset\TestLibraryDiscovery + * @var \Drupal\Core\Asset\LibraryDiscoveryParser|\Drupal\Tests\Core\Asset\TestLibraryDiscoveryParser */ - protected $libraryDiscovery; + protected $libraryDiscoveryParser; /** * The mocked cache backend. @@ -58,18 +57,18 @@ 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} */ public static function getInfo() { return array( - 'name' => 'Tests \Drupal\Core\Asset\LibraryProvider', + 'name' => 'Tests \Drupal\Core\Asset\LibraryDiscoveryParser', 'description' => '', 'group' => 'Asset handling', ); @@ -79,19 +78,16 @@ class LibraryDiscoveryTest extends UnitTestCase { * {@inheritdoc} */ 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->libraryDiscoveryParser = new TestLibraryDiscoveryParser($this->moduleHandler); } /** * Tests that basic functionality works for getLibraryByName. * - * @covers ::getLibraryByName() - * @covers ::buildLibrariesByExtension() + * @covers ::buildByExtension() */ - public function testGetLibraryByNameSimple() { + public function testBuildLibrariesByExtensionSimple() { $this->moduleHandler->expects($this->atLeastOnce()) ->method('moduleExists') ->with('example_module') @@ -99,9 +95,11 @@ class LibraryDiscoveryTest extends UnitTestCase { $path = __DIR__ . '/library_test_files'; $path = substr($path, strlen(DRUPAL_ROOT) + 1); - $this->libraryDiscovery->setPaths('module', 'example_module', $path); + $this->libraryDiscoveryParser->setPaths('module', 'example_module', $path); + + $libraries = $this->libraryDiscoveryParser->buildByExtension('example_module', 'example'); + $library = $libraries['example']; - $library = $this->libraryDiscovery->getLibraryByName('example_module', 'example'); $this->assertCount(0, $library['js']); $this->assertCount(1, $library['css']); $this->assertCount(0, $library['dependencies']); @@ -111,34 +109,12 @@ class LibraryDiscoveryTest extends UnitTestCase { $this->assertEquals(\Drupal::VERSION, $library['version']); } - /** - * Tests that basic functionality works for getLibrariesByExtension. - * - * @covers ::getLibrariesByExtension() - * @covers ::buildLibrariesByExtension() - */ - public function testGetLibrariesByExtensionSimple() { - $this->moduleHandler->expects($this->atLeastOnce()) - ->method('moduleExists') - ->with('example_module') - ->will($this->returnValue(TRUE)); - - $path = __DIR__ . '/library_test_files'; - $path = substr($path, strlen(DRUPAL_ROOT) + 1); - $this->libraryDiscovery->setPaths('module', 'example_module', $path); - - $libraries = $this->libraryDiscovery->getLibrariesByExtension('example_module', 'example'); - $this->assertCount(1, $libraries); - $this->assertEquals($path . '/css/example.css', $libraries['example']['css'][0]['data']); - } - /** * Tests that a theme can be used instead of a module. * - * @covers ::getLibraryByName() - * @covers ::buildLibrariesByExtension() + * @covers ::buildByExtension() */ - public function testGetLibraryByNameWithTheme() { + public function testBuildLibrariesByExtensionWithTheme() { $this->moduleHandler->expects($this->atLeastOnce()) ->method('moduleExists') ->with('example_theme') @@ -146,9 +122,11 @@ class LibraryDiscoveryTest extends UnitTestCase { $path = __DIR__ . '/library_test_files'; $path = substr($path, strlen(DRUPAL_ROOT) + 1); - $this->libraryDiscovery->setPaths('theme', 'example_theme', $path); + $this->libraryDiscoveryParser->setPaths('theme', 'example_theme', $path); + + $libraries = $this->libraryDiscoveryParser->buildByExtension('example_theme'); + $library = $libraries['example']; - $library = $this->libraryDiscovery->getLibraryByName('example_theme', 'example'); $this->assertCount(0, $library['js']); $this->assertCount(1, $library['css']); $this->assertCount(0, $library['dependencies']); @@ -158,11 +136,9 @@ class LibraryDiscoveryTest extends UnitTestCase { /** * Tests that a module with a missing library file results in FALSE. * - * @covers ::getLibraryByName() - * @covers ::getLibrariesByExtension() - * @covers ::buildLibrariesByExtension() + * @covers ::buildByExtension() */ - public function testGetLibraryWithMissingLibraryFile() { + public function testBuildLibrariesByExtensionWithMissingLibraryFile() { $this->moduleHandler->expects($this->atLeastOnce()) ->method('moduleExists') ->with('example_module') @@ -170,10 +146,9 @@ class LibraryDiscoveryTest extends UnitTestCase { $path = __DIR__ . '/library_test_files_not_existing'; $path = substr($path, strlen(DRUPAL_ROOT) + 1); - $this->libraryDiscovery->setPaths('module', 'example_module', $path); + $this->libraryDiscoveryParser->setPaths('module', 'example_module', $path); - $this->assertFalse($this->libraryDiscovery->getLibraryByName('example_module', 'example')); - $this->assertFalse($this->libraryDiscovery->getLibrariesByExtension('example_module')); + $this->assertSame($this->libraryDiscoveryParser->buildByExtension('example_module'), array()); } /** @@ -181,7 +156,7 @@ class LibraryDiscoveryTest extends UnitTestCase { * * @expectedException \Drupal\Core\Asset\Exception\InvalidLibraryFileException * - * @covers ::buildLibrariesByExtension() + * @covers ::buildByExtension() */ public function testInvalidLibrariesFile() { $this->moduleHandler->expects($this->atLeastOnce()) @@ -191,9 +166,9 @@ class LibraryDiscoveryTest extends UnitTestCase { $path = __DIR__ . '/library_test_files'; $path = substr($path, strlen(DRUPAL_ROOT) + 1); - $this->libraryDiscovery->setPaths('module', 'invalid_file', $path); + $this->libraryDiscoveryParser->setPaths('module', 'invalid_file', $path); - $this->libraryDiscovery->getLibrariesByExtension('invalid_file'); + $this->libraryDiscoveryParser->buildByExtension('invalid_file'); } /** @@ -202,9 +177,9 @@ class LibraryDiscoveryTest extends UnitTestCase { * @expectedException \Drupal\Core\Asset\Exception\IncompleteLibraryDefinitionException * @expectedExceptionMessage Incomplete library definition for 'example' in core/tests/Drupal/Tests/Core/Asset/library_test_files/example_module_missing_information.libraries.yml * - * @covers ::buildLibrariesByExtension() + * @covers ::buildByExtension() */ - public function testGetLibraryWithMissingInformation() { + public function testBuildLibrariesByExtensionWithMissingInformation() { $this->moduleHandler->expects($this->atLeastOnce()) ->method('moduleExists') ->with('example_module_missing_information') @@ -212,15 +187,15 @@ class LibraryDiscoveryTest extends UnitTestCase { $path = __DIR__ . '/library_test_files'; $path = substr($path, strlen(DRUPAL_ROOT) + 1); - $this->libraryDiscovery->setPaths('module', 'example_module_missing_information', $path); + $this->libraryDiscoveryParser->setPaths('module', 'example_module_missing_information', $path); - $this->libraryDiscovery->getLibrariesByExtension('example_module_missing_information'); + $this->libraryDiscoveryParser->buildByExtension('example_module_missing_information'); } /** * Tests that the version property of external libraries is handled. * - * @covers ::buildLibrariesByExtension() + * @covers ::buildByExtension() */ public function testExternalLibraries() { $this->moduleHandler->expects($this->atLeastOnce()) @@ -230,9 +205,11 @@ class LibraryDiscoveryTest extends UnitTestCase { $path = __DIR__ . '/library_test_files'; $path = substr($path, strlen(DRUPAL_ROOT) + 1); - $this->libraryDiscovery->setPaths('module', 'external', $path); + $this->libraryDiscoveryParser->setPaths('module', 'external', $path); + + $libraries = $this->libraryDiscoveryParser->buildByExtension('external', 'example_external'); + $library = $libraries['example_external']; - $library = $this->libraryDiscovery->getLibraryByName('external', 'example_external'); $this->assertEquals($path . '/css/example_external.css', $library['css'][0]['data']); $this->assertEquals('3.14', $library['version']); } @@ -240,7 +217,7 @@ class LibraryDiscoveryTest extends UnitTestCase { /** * Ensures that CSS weights are taken into account properly. * - * @covers ::buildLibrariesByExtension() + * @covers ::buildByExtension() */ public function testDefaultCssWeights() { $this->moduleHandler->expects($this->atLeastOnce()) @@ -250,9 +227,10 @@ class LibraryDiscoveryTest extends UnitTestCase { $path = __DIR__ . '/library_test_files'; $path = substr($path, strlen(DRUPAL_ROOT) + 1); - $this->libraryDiscovery->setPaths('module', 'css_weights', $path); + $this->libraryDiscoveryParser->setPaths('module', 'css_weights', $path); - $library = $this->libraryDiscovery->getLibraryByName('css_weights', 'example'); + $libraries = $this->libraryDiscoveryParser->buildByExtension('css_weights'); + $library = $libraries['example']; $css = $library['css']; $this->assertCount(10, $css); @@ -279,7 +257,7 @@ class LibraryDiscoveryTest extends UnitTestCase { * * @expectedException \UnexpectedValueException * - * @covers ::buildLibrariesByExtension() + * @covers ::buildByExtension() */ public function testJsWithPositiveWeight() { $this->moduleHandler->expects($this->atLeastOnce()) @@ -289,15 +267,15 @@ class LibraryDiscoveryTest extends UnitTestCase { $path = __DIR__ . '/library_test_files'; $path = substr($path, strlen(DRUPAL_ROOT) + 1); - $this->libraryDiscovery->setPaths('module', 'js_positive_weight', $path); + $this->libraryDiscoveryParser->setPaths('module', 'js_positive_weight', $path); - $this->libraryDiscovery->getLibrariesByExtension('js_positive_weight'); + $this->libraryDiscoveryParser->buildByExtension('js_positive_weight'); } /** * Tests a library with CSS/JavaScript and a setting. * - * @covers ::buildLibrariesByExtension() + * @covers ::buildByExtension() */ public function testLibraryWithCssJsSetting() { $this->moduleHandler->expects($this->atLeastOnce()) @@ -307,9 +285,10 @@ class LibraryDiscoveryTest extends UnitTestCase { $path = __DIR__ . '/library_test_files'; $path = substr($path, strlen(DRUPAL_ROOT) + 1); - $this->libraryDiscovery->setPaths('module', 'css_js_settings', $path); + $this->libraryDiscoveryParser->setPaths('module', 'css_js_settings', $path); - $library = $this->libraryDiscovery->getLibraryByName('css_js_settings', 'example'); + $libraries = $this->libraryDiscoveryParser->buildByExtension('css_js_settings'); + $library = $libraries['example']; // Ensures that the group and type are set automatically. $this->assertEquals(-100, $library['js'][0]['group']); @@ -327,7 +306,7 @@ class LibraryDiscoveryTest extends UnitTestCase { /** * Tests a library with dependencies. * - * @covers ::buildLibrariesByExtension() + * @covers ::buildByExtension() */ public function testLibraryWithDependencies() { $this->moduleHandler->expects($this->atLeastOnce()) @@ -337,9 +316,11 @@ class LibraryDiscoveryTest extends UnitTestCase { $path = __DIR__ . '/library_test_files'; $path = substr($path, strlen(DRUPAL_ROOT) + 1); - $this->libraryDiscovery->setPaths('module', 'dependencies', $path); + $this->libraryDiscoveryParser->setPaths('module', 'dependencies', $path); + + $libraries = $this->libraryDiscoveryParser->buildByExtension('dependencies'); + $library = $libraries['example']; - $library = $this->libraryDiscovery->getLibraryByName('dependencies', 'example'); $this->assertCount(2, $library['dependencies']); $this->assertEquals('external/example_external', $library['dependencies'][0]); $this->assertEquals('example_module/example', $library['dependencies'][1]); @@ -348,7 +329,7 @@ class LibraryDiscoveryTest extends UnitTestCase { /** * Tests a library with a couple of data formats like full URL. * - * @covers ::buildLibrariesByExtension() + * @covers ::buildByExtension() */ public function testLibraryWithDataTypes() { $this->moduleHandler->expects($this->atLeastOnce()) @@ -358,12 +339,14 @@ class LibraryDiscoveryTest extends UnitTestCase { $path = __DIR__ . '/library_test_files'; $path = substr($path, strlen(DRUPAL_ROOT) + 1); - $this->libraryDiscovery->setPaths('module', 'data_types', $path); + $this->libraryDiscoveryParser->setPaths('module', 'data_types', $path); - $this->libraryDiscovery->setFileValidUri('public://test.css', TRUE); - $this->libraryDiscovery->setFileValidUri('public://test2.css', FALSE); + $this->libraryDiscoveryParser->setFileValidUri('public://test.css', TRUE); + $this->libraryDiscoveryParser->setFileValidUri('public://test2.css', FALSE); + + $libraries = $this->libraryDiscoveryParser->buildByExtension('data_types'); + $library = $libraries['example']; - $library = $this->libraryDiscovery->getLibraryByName('data_types', 'example'); $this->assertCount(5, $library['css']); $this->assertEquals('external', $library['css'][0]['type']); $this->assertEquals('http://example.com/test.css', $library['css'][0]['data']); @@ -375,101 +358,12 @@ class LibraryDiscoveryTest extends UnitTestCase { $this->assertEquals('public://test.css', $library['css'][3]['data']); } - /** - * Tests the internal static cache. - * - * @covers ::ensureLibraryInformation() - */ - public function testStaticCache() { - $this->moduleHandler->expects($this->once()) - ->method('moduleExists') - ->with('example_module') - ->will($this->returnValue(TRUE)); - $this->cache->expects($this->once()) - ->method('get') - ->with('library:info:' . 'example_module') - ->will($this->returnValue(NULL)); - - $path = __DIR__ . '/library_test_files'; - $path = substr($path, strlen(DRUPAL_ROOT) + 1); - $this->libraryDiscovery->setPaths('module', 'example_module', $path); - - $library = $this->libraryDiscovery->getLibraryByName('example_module', 'example'); - $this->assertEquals($path . '/css/example.css', $library['css'][0]['data']); - - $library = $this->libraryDiscovery->getLibraryByName('example_module', 'example'); - $this->assertEquals($path . '/css/example.css', $library['css'][0]['data']); - } - - /** - * Tests the external cache. - * - * @covers ::getCache() - */ - public function testExternalCache() { - // Ensure that the module handler does not need to be touched. - $this->moduleHandler->expects($this->never()) - ->method('moduleExists'); - - $path = __DIR__ . '/library_test_files'; - $path = substr($path, strlen(DRUPAL_ROOT) + 1); - - // Setup a cache entry which will be retrieved, but just once, so the static - // cache still works. - $this->cache->expects($this->once()) - ->method('get') - ->with('library:info:' . 'example_module') - ->will($this->returnValue((object) array( - 'data' => array( - 'example' => array( - 'css' => array( - array( - 'data' => $path . '/css/example.css', - ), - ), - ), - ) - ))); - - $library = $this->libraryDiscovery->getLibraryByName('example_module', 'example'); - $this->assertEquals($path . '/css/example.css', $library['css'][0]['data']); - - $library = $this->libraryDiscovery->getLibraryByName('example_module', 'example'); - $this->assertEquals($path . '/css/example.css', $library['css'][0]['data']); - } - - /** - * Tests setting the external cache. - * - * @covers ::setCache() - */ - public function testSetCache() { - $this->moduleHandler->expects($this->once()) - ->method('moduleExists') - ->with('example_module') - ->will($this->returnValue(TRUE)); - - $path = __DIR__ . '/library_test_files'; - $path = substr($path, strlen(DRUPAL_ROOT) + 1); - $this->libraryDiscovery->setPaths('module', 'example_module', $path); - - $this->cache->expects($this->once()) - ->method('set') - ->with('library:info:example_module', $this->isType('array'), Cache::PERMANENT, array( - 'extension' => array(TRUE, 'example_module'), - 'library_info' => array(TRUE), - )); - - $library = $this->libraryDiscovery->getLibraryByName('example_module', 'example'); - $this->assertEquals($path . '/css/example.css', $library['css'][0]['data']); - } - } /** * Wraps the tested class to mock the external dependencies. */ -class TestLibraryDiscovery extends LibraryDiscovery { +class TestLibraryDiscoveryParser extends LibraryDiscoveryParser { protected $paths;