diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc index 5d81ac1..7f5e3d2 100644 --- a/core/includes/bootstrap.inc +++ b/core/includes/bootstrap.inc @@ -228,10 +228,23 @@ function config_get_config_directory($type = CONFIG_ACTIVE_DIRECTORY) { * The filename of the requested item or NULL if the item is not found. */ function drupal_get_filename($type, $name, $filename = NULL) { + // Return NULL right away if $type or $name is empty. + if (empty($type) || empty($name)) { + return NULL; + } + // The location of files will not change during the request, so do not use // drupal_static(). static $files = array(); + // We use drupal static for the bad records so we can test it. + // Drupal static fast pattern is used as this function may be called often. + static $drupal_static_fast; + if (!isset($drupal_static_fast)) { + $drupal_static_fast['bad'] = &drupal_static(__FUNCTION__ . ':bad'); + } + $bad = &$drupal_static_fast['bad']; + // Type 'core' only exists to simplify application-level logic; it always maps // to the /core directory, whereas $name is ignored. It is only requested via // drupal_get_path(). /core/core.info.yml does not exist, but is required @@ -270,13 +283,24 @@ function drupal_get_filename($type, $name, $filename = NULL) { } // If still unknown, perform a filesystem scan. if (!isset($files[$type][$name])) { - $listing = new ExtensionDiscovery(DRUPAL_ROOT); - // Prevent an infinite recursion by this legacy function. - if ($original_type == 'profile') { - $listing->setProfileDirectories(array()); + if (is_null($bad)) { + $bad = array(); + if (\Drupal::hasService('cache.bootstrap')) { + $cache = Drupal::cache('bootstrap')->get('drupal_get_filename:bad', TRUE); + if ($cache && $cache->data) { + $bad = $cache->data; + } + } } - foreach ($listing->scan($original_type) as $extension_name => $file) { - $files[$type][$extension_name] = $file->getPathname(); + if (!isset($bad[$type][$name])) { + $listing = new ExtensionDiscovery(DRUPAL_ROOT); + // Prevent an infinite recursion by this legacy function. + if ($original_type == 'profile') { + $listing->setProfileDirectories(array()); + } + foreach ($listing->scan($original_type) as $extension_name => $file) { + $files[$type][$extension_name] = $file->getPathname(); + } } } } @@ -284,6 +308,16 @@ function drupal_get_filename($type, $name, $filename = NULL) { if (isset($files[$type][$name])) { return $files[$type][$name]; } + elseif (!isset($bad[$type][$name])) { + // Add the missing file to a temporary cache and throw an alert. + $bad[$type][$name] = TRUE; + if (\Drupal::hasService('cache.bootstrap')) { + \Drupal::cache('bootstrap')->set('drupal_get_filename:bad', $bad, REQUEST_TIME); + } + if (\Drupal::hasService('logger.factory')) { + \Drupal::logger('system')->error('The following @type is missing from the file system: @name', array('@type' => $type, '@name' => $name)); + } + } } /** diff --git a/core/lib/Drupal/Core/Config/ExtensionInstallStorage.php b/core/lib/Drupal/Core/Config/ExtensionInstallStorage.php index cb2833e..cbe3ae8 100644 --- a/core/lib/Drupal/Core/Config/ExtensionInstallStorage.php +++ b/core/lib/Drupal/Core/Config/ExtensionInstallStorage.php @@ -99,7 +99,11 @@ protected function getAllFolders() { // The install profile can override module default configuration. We do // this by replacing the config file path from the module/theme with the // install profile version if there are any duplicates. - $profile_folders = $this->getComponentNames('profile', array(drupal_get_profile())); + $profile_folders = array(); + $profile = drupal_get_profile(); + if (!empty($profile)) { + $profile_folders = $this->getComponentNames('profile', array($profile)); + } $folders_to_replace = array_intersect_key($profile_folders, $this->folders); if (!empty($folders_to_replace)) { $this->folders = array_merge($this->folders, $folders_to_replace); diff --git a/core/modules/system/src/Tests/Bootstrap/GetFilenameUnitTest.php b/core/modules/system/src/Tests/Bootstrap/GetFilenameUnitTest.php index 9baf5cd..12a32c9 100644 --- a/core/modules/system/src/Tests/Bootstrap/GetFilenameUnitTest.php +++ b/core/modules/system/src/Tests/Bootstrap/GetFilenameUnitTest.php @@ -70,7 +70,16 @@ function testDrupalGetFilename() { // a fixed location and naming. $this->assertIdentical(drupal_get_filename('profile', 'standard'), 'core/profiles/standard/standard.info.yml'); + // Generate a non-existing module name. + $non_existing_module = uniqid("", TRUE); + // Searching for an item that does not exist returns NULL. - $this->assertNull(drupal_get_filename('module', uniqid("", TRUE)), 'Searching for an item that does not exist returns NULL.'); + $this->assertNull(drupal_get_filename('module', $non_existing_module), 'Searching for an item that does not exist returns NULL.'); + + // Get the bad records static from drupal_get_filename. + $bad = &drupal_static('drupal_get_filename:bad'); + + // Searching for an item that does not exist creates a static record in drupal_get_filename. + $this->assertTrue($bad['module'][$non_existing_module], 'Searching for an item that does not exist creates a static record in drupal_get_filename.'); } }