diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc index eeacd7a..e8808c2 100644 --- a/core/includes/bootstrap.inc +++ b/core/includes/bootstrap.inc @@ -249,16 +249,9 @@ function drupal_get_filename($type, $name, $filename = NULL) { if (!isset($files[$type][$name]) && \Drupal::hasService('state')) { $files[$type] += \Drupal::state()->get('system.' . $type . '.files', array()); } - // If still unknown, perform a filesystem scan. + // If still unknown, create a user-level error message. 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()); - } - foreach ($listing->scan($original_type) as $extension_name => $file) { - $files[$type][$extension_name] = $file->getPathname(); - } + trigger_error(SafeMarkup::format('The following @type is missing from the file system: @name', array('@type' => $type, '@name' => $name)), E_USER_WARNING); } } diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc index d858875..dd1d5e9 100644 --- a/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -302,6 +302,10 @@ function install_begin_request($class_loader, &$install_state) { // Allow command line scripts to override server variables used by Drupal. require_once __DIR__ . '/bootstrap.inc'; + // Prime the drupal_get_filename() cache with the location of the system + // module. + drupal_get_filename('module', 'system', 'core/modules/system/system.info.yml'); + // If the hash salt leaks, it becomes possible to forge a valid testing user // agent, install a new copy of Drupal, and take over the original site. // The user agent header is used to pass a database prefix in the request when @@ -1031,6 +1035,7 @@ function install_base_system(&$install_state) { // Enable the user module so that sessions can be recorded during the // upcoming bootstrap step. + system_rebuild_module_data(); \Drupal::service('module_installer')->install(array('user'), FALSE); // Save the list of other modules to install for the upcoming tasks. diff --git a/core/includes/install.inc b/core/includes/install.inc index 7e0e32e..604c82d 100644 --- a/core/includes/install.inc +++ b/core/includes/install.inc @@ -922,11 +922,19 @@ function drupal_check_profile($profile, array $install_state) { // Collect requirement testing results. $requirements = array(); + + $listing = new ExtensionDiscovery(DRUPAL_ROOT); + $module_list = $listing->scan('module'); + // Make sure the installation API is available + include_once __DIR__ . '/install.inc'; foreach ($info['dependencies'] as $module) { - module_load_install($module); + $file = DRUPAL_ROOT . '/' . $module_list[$module]->getPath() . "/$module.install"; + if (is_file($file)) { + require_once $file; + } $function = $module . '_requirements'; - drupal_classloader_register($module, drupal_get_path('module', $module)); + drupal_classloader_register($module, $module_list[$module]->getPath()); if (function_exists($function)) { $requirements = array_merge($requirements, $function('install')); } diff --git a/core/lib/Drupal/Core/Config/ConfigInstaller.php b/core/lib/Drupal/Core/Config/ConfigInstaller.php index c109ea7..d87c142 100644 --- a/core/lib/Drupal/Core/Config/ConfigInstaller.php +++ b/core/lib/Drupal/Core/Config/ConfigInstaller.php @@ -157,17 +157,23 @@ public function installDefaultConfig($type, $name) { * {@inheritdoc} */ public function installOptionalConfig(StorageInterface $storage = NULL, $dependency = []) { + $profile = $this->drupalGetProfile(); if (!$storage) { // Search the install profile's optional configuration too. $storage = new ExtensionInstallStorage($this->getActiveStorages(StorageInterface::DEFAULT_COLLECTION), InstallStorage::CONFIG_OPTIONAL_DIRECTORY, StorageInterface::DEFAULT_COLLECTION, TRUE); // The extension install storage ensures that overrides are used. $profile_storage = NULL; } - else { + elseif (isset($profile)) { // Creates a profile storage to search for overrides. - $profile_install_path = $this->drupalGetPath('module', $this->drupalGetProfile()) . '/' . InstallStorage::CONFIG_OPTIONAL_DIRECTORY; + $profile_install_path = $this->drupalGetPath('module', $profile) . '/' . InstallStorage::CONFIG_OPTIONAL_DIRECTORY; $profile_storage = new FileStorage($profile_install_path, StorageInterface::DEFAULT_COLLECTION); } + else { + // Profile has not been set yet. For example during the first steps of the + // installer or during unit tests. + $profile_storage = NULL; + } $collection_info = $this->configManager->getConfigCollectionInfo(); $enabled_extensions = $this->getEnabledExtensions(); diff --git a/core/lib/Drupal/Core/Config/ExtensionInstallStorage.php b/core/lib/Drupal/Core/Config/ExtensionInstallStorage.php index 15490b4..b75ef3c 100644 --- a/core/lib/Drupal/Core/Config/ExtensionInstallStorage.php +++ b/core/lib/Drupal/Core/Config/ExtensionInstallStorage.php @@ -8,6 +8,7 @@ namespace Drupal\Core\Config; use Drupal\Core\Site\Settings; +use Drupal\Core\Extension\ExtensionDiscovery; /** * Storage to access configuration and schema in enabled extensions. @@ -80,26 +81,40 @@ public function createCollection($collection) { protected function getAllFolders() { if (!isset($this->folders)) { $this->folders = array(); - $this->folders += $this->getComponentNames('core', array('core')); + $this->folders += $this->getCoreNames(); $install_profile = Settings::get('install_profile'); $extensions = $this->configStorage->read('core.extension'); + $listing = new ExtensionDiscovery(DRUPAL_ROOT); if (!empty($extensions['module'])) { $modules = $extensions['module']; // Remove the install profile as this is handled later. unset($modules[$install_profile]); - $this->folders += $this->getComponentNames('module', array_keys($modules)); + $module_list_scan = $listing->scan('module'); + $module_list = array(); + foreach (array_keys($modules) as $module) { + $module_list[$module] = $module_list_scan[$module]; + } + $this->folders += $this->getComponentNames($module_list); } if (!empty($extensions['theme'])) { - $this->folders += $this->getComponentNames('theme', array_keys($extensions['theme'])); + $theme_list_scan = $listing->scan('theme'); + foreach (array_keys($extensions['theme']) as $theme) { + $theme_list[$theme] = $theme_list_scan[$theme]; + } + $this->folders += $this->getComponentNames($theme_list); } if ($this->includeProfile) { // 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())); - $this->folders = $profile_folders + $this->folders; + $profile = drupal_get_profile(); + if (isset($profile)) { + $profile_list = $listing->scan('profile'); + $profile_folders = $this->getComponentNames(array($profile_list[$profile])); + $this->folders = $profile_folders + $this->folders; + } } } return $this->folders; diff --git a/core/lib/Drupal/Core/Config/InstallStorage.php b/core/lib/Drupal/Core/Config/InstallStorage.php index 06618d7..800b668 100644 --- a/core/lib/Drupal/Core/Config/InstallStorage.php +++ b/core/lib/Drupal/Core/Config/InstallStorage.php @@ -8,6 +8,7 @@ namespace Drupal\Core\Config; use Drupal\Core\Extension\ExtensionDiscovery; +use Drupal\Core\Extension\Extension; /** * Storage used by the Drupal installer. @@ -157,14 +158,14 @@ public function listAll($prefix = '') { protected function getAllFolders() { if (!isset($this->folders)) { $this->folders = array(); - $this->folders += $this->getComponentNames('core', array('core')); - // @todo Refactor getComponentNames() to use the extension list directly. + $this->folders += $this->getCoreNames(); + $listing = new ExtensionDiscovery(DRUPAL_ROOT); if ($profile = drupal_get_profile()) { - $this->folders += $this->getComponentNames('profile', array($profile)); + $profile_list = $listing->scan('profile'); + $this->folders += $this->getComponentNames(array($profile_list[$profile])); } - $listing = new ExtensionDiscovery(DRUPAL_ROOT); - $this->folders += $this->getComponentNames('module', array_keys($listing->scan('module'))); - $this->folders += $this->getComponentNames('theme', array_keys($listing->scan('theme'))); + $this->folders += $this->getComponentNames($listing->scan('module')); + $this->folders += $this->getComponentNames($listing->scan('theme')); } return $this->folders; } @@ -172,19 +173,17 @@ protected function getAllFolders() { /** * Get all configuration names and folders for a list of modules or themes. * - * @param string $type - * Type of components: 'module' | 'theme' | 'profile' - * @param array $list - * Array of theme or module names. + * @param \Drupal\Core\Extension\Extension[] $list + * An associative array of Extension objects, keyed by extension name. * * @return array * Folders indexed by configuration name. */ - public function getComponentNames($type, array $list) { + public function getComponentNames(array $list) { $extension = '.' . $this->getFileExtension(); $folders = array(); - foreach ($list as $name) { - $directory = $this->getComponentFolder($type, $name); + foreach ($list as $extension_object) { + $directory = $this->getComponentFolder($extension_object); if (file_exists($directory)) { $files = new \GlobIterator(DRUPAL_ROOT . '/' . $directory . '/*' . $extension); foreach ($files as $file) { @@ -196,18 +195,45 @@ public function getComponentNames($type, array $list) { } /** + * Get all configuration names and folders for Drupal core. + * + * @return array + * Folders indexed by configuration name. + */ + public function getCoreNames() { + $extension = '.' . $this->getFileExtension(); + $folders = array(); + $directory = $this->getCoreFolder(); + if (file_exists($directory)) { + $files = new \GlobIterator(DRUPAL_ROOT . '/' . $directory . '/*' . $extension); + foreach ($files as $file) { + $folders[$file->getBasename($extension)] = $directory; + } + } + return $folders; + } + + /** * Get folder inside each component that contains the files. * - * @param string $type - * Component type: 'module' | 'theme' | 'profile' - * @param string $name - * Component name. + * @param \Drupal\Core\Extension\Extension $extension + * The Extension object for the component. * * @return string * The configuration folder name for this component. */ - protected function getComponentFolder($type, $name) { - return drupal_get_path($type, $name) . '/' . $this->getCollectionDirectory(); + protected function getComponentFolder(Extension $extension) { + return $extension->getPath() . '/' . $this->getCollectionDirectory(); + } + + /** + * Get folder inside Drupal core that contains the files. + * + * @return string + * The configuration folder name for core. + */ + protected function getCoreFolder() { + return drupal_get_path('core', 'core') . '/' . $this->getCollectionDirectory(); } /** diff --git a/core/lib/Drupal/Core/Extension/ModuleInstaller.php b/core/lib/Drupal/Core/Extension/ModuleInstaller.php index caddbad..af53b82 100644 --- a/core/lib/Drupal/Core/Extension/ModuleInstaller.php +++ b/core/lib/Drupal/Core/Extension/ModuleInstaller.php @@ -18,7 +18,7 @@ /** * Default implementation of the module installer. * - * It registers the module in config, install its own configuration, + * It registers the module in config, installs its own configuration, * installs the schema, updates the Drupal kernel and more. */ class ModuleInstaller implements ModuleInstallerInterface { diff --git a/core/modules/ckeditor/ckeditor.module b/core/modules/ckeditor/ckeditor.module index 2c2a6a5..1520c5e 100644 --- a/core/modules/ckeditor/ckeditor.module +++ b/core/modules/ckeditor/ckeditor.module @@ -82,7 +82,7 @@ function _ckeditor_theme_css($theme = NULL) { if (!isset($theme)) { $theme = \Drupal::config('system.theme')->get('default'); } - if ($theme_path = drupal_get_path('theme', $theme)) { + if (isset($theme) && $theme_path = drupal_get_path('theme', $theme)) { $info = system_get_info('theme', $theme); if (isset($info['ckeditor_stylesheets'])) { $css = $info['ckeditor_stylesheets']; diff --git a/core/modules/comment/src/Tests/CommentStringIdEntitiesTest.php b/core/modules/comment/src/Tests/CommentStringIdEntitiesTest.php index 3cb8ab0..0285432 100644 --- a/core/modules/comment/src/Tests/CommentStringIdEntitiesTest.php +++ b/core/modules/comment/src/Tests/CommentStringIdEntitiesTest.php @@ -27,7 +27,6 @@ class CommentStringIdEntitiesTest extends KernelTestBase { 'user', 'field', 'field_ui', - 'entity', 'entity_test', 'text', ); diff --git a/core/modules/config/tests/config_test/src/TestInstallStorage.php b/core/modules/config/tests/config_test/src/TestInstallStorage.php index e4b3864..c4ee57e 100644 --- a/core/modules/config/tests/config_test/src/TestInstallStorage.php +++ b/core/modules/config/tests/config_test/src/TestInstallStorage.php @@ -23,13 +23,12 @@ class TestInstallStorage extends InstallStorage { */ protected function getAllFolders() { if (!isset($this->folders)) { - $this->folders = $this->getComponentNames('core', array('core')); - // @todo Refactor getComponentNames() to use the extension list directly. + $this->folders = $this->getCoreNames(); $listing = new ExtensionDiscovery(\Drupal::root()); $listing->setProfileDirectories(array()); - $this->folders += $this->getComponentNames('profile', array_keys($listing->scan('profile'))); - $this->folders += $this->getComponentNames('module', array_keys($listing->scan('module'))); - $this->folders += $this->getComponentNames('theme', array_keys($listing->scan('theme'))); + $this->folders += $this->getComponentNames($listing->scan('profile')); + $this->folders += $this->getComponentNames($listing->scan('module')); + $this->folders += $this->getComponentNames($listing->scan('theme')); } return $this->folders; } diff --git a/core/modules/quickedit/quickedit.module b/core/modules/quickedit/quickedit.module index 6813fe4..38805a2 100644 --- a/core/modules/quickedit/quickedit.module +++ b/core/modules/quickedit/quickedit.module @@ -77,7 +77,7 @@ function quickedit_library_info_alter(&$libraries, $extension) { // First let the base theme modify the library, then the actual theme. $alter_library = function(&$library, $theme) use (&$alter_library) { - if ($theme_path = drupal_get_path('theme', $theme)) { + if (isset($theme) && $theme_path = drupal_get_path('theme', $theme)) { $info = system_get_info('theme', $theme); // Recurse to process base theme(s) first. if (isset($info['base theme'])) { diff --git a/core/modules/system/src/Tests/Bootstrap/GetFilenameUnitTest.php b/core/modules/system/src/Tests/Bootstrap/GetFilenameUnitTest.php index f867045..eeea4aa 100644 --- a/core/modules/system/src/Tests/Bootstrap/GetFilenameUnitTest.php +++ b/core/modules/system/src/Tests/Bootstrap/GetFilenameUnitTest.php @@ -70,7 +70,20 @@ 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); + + // Set a custom error handler so we can ignore the file not found error. + set_error_handler(function($severity, $message, $file, $line) { + // Skip error handling if this is a "file not found" error. + if (!(error_reporting() & $severity) || strstr($message, 'is missing from the file system:')) { + return; + } + throw new ErrorException($message, 0, $severity, $file, $line); + }); // 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.'); + // Restore the original error handler. + restore_error_handler(); } } diff --git a/core/modules/system/src/Tests/Common/AttachedAssetsTest.php b/core/modules/system/src/Tests/Common/AttachedAssetsTest.php index 3251305..8c9c217 100644 --- a/core/modules/system/src/Tests/Common/AttachedAssetsTest.php +++ b/core/modules/system/src/Tests/Common/AttachedAssetsTest.php @@ -74,7 +74,7 @@ function testDefault() { * Tests non-existing libraries. */ function testLibraryUnknown() { - $build['#attached']['library'][] = 'unknown/unknown'; + $build['#attached']['library'][] = 'core/unknown'; $assets = AttachedAssets::createFromRenderArray($build); $this->assertIdentical([], $this->assetResolver->getJsAssets($assets, FALSE)[0], 'Unknown library was not added to the page.'); diff --git a/core/modules/system/src/Tests/Entity/EntitySchemaTest.php b/core/modules/system/src/Tests/Entity/EntitySchemaTest.php index 6f6f39d..5ce61be 100644 --- a/core/modules/system/src/Tests/Entity/EntitySchemaTest.php +++ b/core/modules/system/src/Tests/Entity/EntitySchemaTest.php @@ -24,13 +24,6 @@ class EntitySchemaTest extends EntityUnitTestBase { protected $database; /** - * Modules to enable. - * - * @var array - */ - public static $modules = array('menu_link'); - - /** * {@inheritdoc} */ public function setUp() { diff --git a/core/modules/taxonomy/src/Tests/TermKernelTest.php b/core/modules/taxonomy/src/Tests/TermKernelTest.php index 6692775..3d08826 100644 --- a/core/modules/taxonomy/src/Tests/TermKernelTest.php +++ b/core/modules/taxonomy/src/Tests/TermKernelTest.php @@ -23,7 +23,7 @@ class TermKernelTest extends KernelTestBase { /** * {@inheritdoc} */ - public static $modules = array( 'filter', 'taxonomy', 'taxonomy_term', 'text', 'user' ); + public static $modules = array( 'filter', 'taxonomy', 'text', 'user' ); /** * {@inheritdoc} diff --git a/core/modules/views/src/Tests/Plugin/RowEntityTest.php b/core/modules/views/src/Tests/Plugin/RowEntityTest.php index 35bd1e2..7de0305 100644 --- a/core/modules/views/src/Tests/Plugin/RowEntityTest.php +++ b/core/modules/views/src/Tests/Plugin/RowEntityTest.php @@ -24,7 +24,7 @@ class RowEntityTest extends ViewUnitTestBase { * * @var array */ - public static $modules = ['taxonomy', 'text', 'filter', 'field', 'entity', 'system', 'node', 'user']; + public static $modules = ['taxonomy', 'text', 'filter', 'field', 'system', 'node', 'user']; /** * Views used by this test.