diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc index bae5acfde2..fe26d62fdf 100644 --- a/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -444,7 +444,7 @@ function install_begin_request($class_loader, &$install_state) { $install_state['theme'] = $install_state['profile_info']['distribution']['install']['theme']; } // Ensure all profile directories are registered. - $profiles = \Drupal::service('profile_handler')->getProfiles($profile); + $profiles = \Drupal::service('profile_handler')->getProfileInheritance($profile); $profile_directories = array_map(function($extension) { return $extension->getPath(); }, $profiles); @@ -1575,7 +1575,7 @@ function install_profile_themes(&$install_state) { */ function install_install_profile(&$install_state) { // Install all the profiles. - $profiles = \Drupal::service('profile_handler')->getProfiles(); + $profiles = \Drupal::service('profile_handler')->getProfileInheritance(); \Drupal::service('module_installer')->install(array_keys($profiles), FALSE); // Install all available optional config. During installation the module order diff --git a/core/lib/Drupal/Core/Config/ConfigInstaller.php b/core/lib/Drupal/Core/Config/ConfigInstaller.php index bcb2144df7..9cd33c0b0a 100644 --- a/core/lib/Drupal/Core/Config/ConfigInstaller.php +++ b/core/lib/Drupal/Core/Config/ConfigInstaller.php @@ -482,7 +482,7 @@ public function checkConfigurationToInstall($type, $name) { // Install profiles can not have config clashes. Configuration that // has the same name as a module's configuration will be used instead. - $profiles = $this->profileHandler->getProfiles(); + $profiles = $this->profileHandler->getProfileInheritance(); if (!isset($profiles[$name])) { // Throw an exception if the module being installed contains configuration // that already exists. Additionally, can not continue installing more diff --git a/core/lib/Drupal/Core/Config/ExtensionInstallStorage.php b/core/lib/Drupal/Core/Config/ExtensionInstallStorage.php index 2ad1ae35a0..c3a026b5a4 100644 --- a/core/lib/Drupal/Core/Config/ExtensionInstallStorage.php +++ b/core/lib/Drupal/Core/Config/ExtensionInstallStorage.php @@ -125,7 +125,7 @@ protected function getAllFolders() { // 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. - $this->folders += $this->getComponentNames($this->profileHandler->getProfiles($this->installProfile)); + $this->folders += $this->getComponentNames($this->profileHandler->getProfileInheritance($this->installProfile)); } } return $this->folders; diff --git a/core/lib/Drupal/Core/Config/InstallStorage.php b/core/lib/Drupal/Core/Config/InstallStorage.php index fad317a4d9..23bf7494a4 100644 --- a/core/lib/Drupal/Core/Config/InstallStorage.php +++ b/core/lib/Drupal/Core/Config/InstallStorage.php @@ -165,7 +165,7 @@ protected function getAllFolders() { $this->folders = []; $this->folders += $this->getCoreNames(); // Get dependent profiles and add the extension components. - $this->folders += $this->getComponentNames($this->profileHandler->getProfiles()); + $this->folders += $this->getComponentNames($this->profileHandler->getProfileInheritance()); // Perform an ExtensionDiscovery scan as we cannot use drupal_get_path() // yet because the system module may not yet be enabled during install. // @todo Remove as part of https://www.drupal.org/node/2186491 diff --git a/core/lib/Drupal/Core/EventSubscriber/ConfigImportSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/ConfigImportSubscriber.php index bb63b0770f..03d84061d3 100644 --- a/core/lib/Drupal/Core/EventSubscriber/ConfigImportSubscriber.php +++ b/core/lib/Drupal/Core/EventSubscriber/ConfigImportSubscriber.php @@ -122,7 +122,7 @@ protected function validateModules(ConfigImporter $config_importer) { // Get a list of parent profiles and the main profile. /* @var $profiles \Drupal\Core\Extension\Extension[] */ - $profiles = \Drupal::service('profile_handler')->getProfiles(); + $profiles = \Drupal::service('profile_handler')->getProfileInheritance(); /* @var $main_profile \Drupal\Core\Extension\Extension */ $main_profile = end($profiles); diff --git a/core/lib/Drupal/Core/Extension/ExtensionDiscovery.php b/core/lib/Drupal/Core/Extension/ExtensionDiscovery.php index 1996db4de9..6774594069 100644 --- a/core/lib/Drupal/Core/Extension/ExtensionDiscovery.php +++ b/core/lib/Drupal/Core/Extension/ExtensionDiscovery.php @@ -265,7 +265,7 @@ public function setProfileDirectoriesFromSettings() { // In case both profile directories contain the same extension, the actual // profile always has precedence. if ($profile) { - $profiles = $this->profileHandler->getProfiles($profile); + $profiles = $this->profileHandler->getProfileInheritance($profile); $profile_directories = array_map(function($extension) { return $extension->getPath(); }, $profiles); diff --git a/core/lib/Drupal/Core/Extension/FallbackProfileHandler.php b/core/lib/Drupal/Core/Extension/FallbackProfileHandler.php index f858ca21ab..c8f18bec0d 100644 --- a/core/lib/Drupal/Core/Extension/FallbackProfileHandler.php +++ b/core/lib/Drupal/Core/Extension/FallbackProfileHandler.php @@ -38,7 +38,9 @@ public function getProfileInfo($profile) { if (isset($this->profileInfo[$profile])) { return $this->profileInfo[$profile]; } - return []; + else { + throw new \InvalidArgumentException('The profile name is invalid.'); + } } /** @@ -51,14 +53,14 @@ public function setProfileInfo($profile, array $info) { /** * {@inheritdoc} */ - public function clearProfileCache() { + public function clearCache() { unset($this->profileInfo); } /** * {@inheritdoc} */ - public function getProfiles($profile = NULL) { + public function getProfileInheritance($profile = NULL) { $profile_path = drupal_get_path('profile', $profile); return [ $profile => new Extension($this->root, 'profile', $profile_path), diff --git a/core/lib/Drupal/Core/Extension/ModuleInstaller.php b/core/lib/Drupal/Core/Extension/ModuleInstaller.php index 9102d7783d..64bc322dce 100644 --- a/core/lib/Drupal/Core/Extension/ModuleInstaller.php +++ b/core/lib/Drupal/Core/Extension/ModuleInstaller.php @@ -334,7 +334,7 @@ public function uninstall(array $module_list, $uninstall_dependents = TRUE) { if ($uninstall_dependents) { // Add dependent modules to the list. The new modules will be processed as // the while loop continues. - $profiles = \Drupal::service('profile_handler')->getProfiles(); + $profiles = \Drupal::service('profile_handler')->getProfileInheritance(); while (list($module) = each($module_list)) { foreach (array_keys($module_data[$module]->required_by) as $dependent) { if (!isset($module_data[$dependent])) { diff --git a/core/lib/Drupal/Core/Extension/ProfileHandler.php b/core/lib/Drupal/Core/Extension/ProfileHandler.php index b429972fdb..fa2cfaf110 100644 --- a/core/lib/Drupal/Core/Extension/ProfileHandler.php +++ b/core/lib/Drupal/Core/Extension/ProfileHandler.php @@ -151,6 +151,7 @@ public function getProfileInfo($profile) { // Ensure all dependencies are cleanly merged. $info['dependencies'] = array_merge($info['dependencies'], $base_info['dependencies']); + if (isset($info['base profile']['excluded_dependencies'])) { // Apply excluded dependencies. $info['dependencies'] = array_diff($info['dependencies'], $info['base profile']['excluded_dependencies']); @@ -198,7 +199,7 @@ public function setProfileInfo($profile, array $info) { /** * {@inheritdoc} */ - public function clearProfileCache() { + public function clearCache() { $this->profilesWithParentsCache = []; $this->infoCache = []; } @@ -238,8 +239,8 @@ protected function getProfileExtension($profile) { * * @return string[] * An associative array of profile names, keyed by profile name - * in descending order of their dependencies. - * (parent profiles first, main profile last) + * in descending order of their dependencies (parent profiles first, main + * profile last). */ protected function getProfileList($profile) { $profile_info = $this->getProfileInfo($profile); @@ -249,7 +250,7 @@ protected function getProfileList($profile) { /** * {@inheritdoc} */ - public function getProfiles($profile = NULL) { + public function getProfileInheritance($profile = NULL) { if (empty($profile)) { $profile = drupal_get_profile(); } @@ -280,7 +281,7 @@ public function getProfiles($profile = NULL) { * {@inheritdoc} */ public function selectDistribution(array $profile_list) { - // First, find all profiles marked as distributions + // First, find all profiles marked as distributions. $distributions = []; foreach ($profile_list as $profile_name) { $profile_info = $this->getProfileInfo($profile_name); diff --git a/core/lib/Drupal/Core/Extension/ProfileHandlerInterface.php b/core/lib/Drupal/Core/Extension/ProfileHandlerInterface.php index 37b4bdf002..e2ce9b98fd 100644 --- a/core/lib/Drupal/Core/Extension/ProfileHandlerInterface.php +++ b/core/lib/Drupal/Core/Extension/ProfileHandlerInterface.php @@ -10,7 +10,7 @@ /** * Retrieve the info array for a profile. * - * Parse and process the profile info.yml file. + * Parses and processes the profile info.yml file. * Processing steps: * 1) Ensure default keys are set. * 2) Recursively collect dependencies from parent profiles. @@ -24,6 +24,9 @@ * @return array * The processed $info array. * + * @throws \InvalidArgumentException + * If the profile name is invalid. + * * @see install_profile_info() */ public function getProfileInfo($profile); @@ -32,7 +35,6 @@ public function getProfileInfo($profile); * Stores info data for a profile. * * This can be used in situations where the info cache needs to be changed - * This is used for testing. * * @param string $profile * The name of profile. @@ -46,20 +48,21 @@ public function setProfileInfo($profile, array $info); /** * Clears the profile cache. */ - public function clearProfileCache(); + public function clearCache(); /** - * Returns a list of dependent installation profiles. + * Gets a list comprised of the profile, it's parent profile if it has one, + * and any further ancestors. * * @param string $profile * The name of profile. If none is specified, use the current profile. * * @return \Drupal\Core\Extension\Extension[] * An associative array of Extension objects, keyed by profile name in - * descending order of their dependencies. - * (parent profiles first, main profile last) + * descending order of their dependencies (parent profiles first, main + * profile last). */ - public function getProfiles($profile = NULL); + public function getProfileInheritance($profile = NULL); /** * Select the install distribution from the list of profiles. diff --git a/core/modules/system/src/Form/ModulesUninstallForm.php b/core/modules/system/src/Form/ModulesUninstallForm.php index bcd60652ba..2cff995d3a 100644 --- a/core/modules/system/src/Form/ModulesUninstallForm.php +++ b/core/modules/system/src/Form/ModulesUninstallForm.php @@ -114,7 +114,7 @@ public function buildForm(array $form, FormStateInterface $form_state) { return $form; } - $profiles = \Drupal::service('profile_handler')->getProfiles(); + $profiles = \Drupal::service('profile_handler')->getProfileInheritance(); // Sort all modules by their name. uasort($uninstallable, 'system_sort_modules_by_info_name'); diff --git a/core/modules/system/system.module b/core/modules/system/system.module index 3d013178a7..5aeab69aa4 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -1000,7 +1000,7 @@ function _system_rebuild_module_data() { // Find profiles. /** @var \Drupal\Core\Extension\ProfileHandlerInterface $profile_handler */ $profile_handler = \Drupal::service('profile_handler'); - $modules = array_merge($modules, $profile_handler->getProfiles()); + $modules = array_merge($modules, $profile_handler->getProfileInheritance()); // Set defaults for module info. $defaults = [ @@ -1044,7 +1044,7 @@ function _system_rebuild_module_data() { } // This must be done after _system_rebuild_module_data_ensure_required(). - $profiles = \Drupal::service('profile_handler')->getProfiles(); + $profiles = \Drupal::service('profile_handler')->getProfileInheritance(); foreach ($profiles as $profile_name => $profile) { if (isset($modules[$profile_name])) { // Installation profiles are required, if it's a valid module. diff --git a/core/profiles/testing_subsubprofile/testing_subsubprofile.info.yml b/core/profiles/testing_subsubprofile/testing_subsubprofile.info.yml new file mode 100644 index 0000000000..74c0b8cf58 --- /dev/null +++ b/core/profiles/testing_subsubprofile/testing_subsubprofile.info.yml @@ -0,0 +1,14 @@ +name: Testing SubSubProfile +type: profile +description: 'Profile for testing deep profile inheritance.' +version: VERSION +core: 8.x +hidden: true + +base profile: + name: testing_inherited + excluded_dependencies: + - config + +dependencies: + - page_cache diff --git a/core/profiles/testing_subsubprofile/tests/src/Functional/DeepInheritedProfileTest.php b/core/profiles/testing_subsubprofile/tests/src/Functional/DeepInheritedProfileTest.php new file mode 100644 index 0000000000..6933de6214 --- /dev/null +++ b/core/profiles/testing_subsubprofile/tests/src/Functional/DeepInheritedProfileTest.php @@ -0,0 +1,35 @@ +assertEquals('stable', $this->config('system.theme')->get('default')); + + // page_cache was enabled in main profile, disabled in parent and enabled + // in this profile. + $this->assertTrue(\Drupal::moduleHandler()->moduleExists('page_cache')); + // block was enabled in parent profile. + $this->assertTrue(\Drupal::moduleHandler()->moduleExists('block')); + // config was enabled in parent profile and disabled in this. + $this->assertFalse(\Drupal::moduleHandler()->moduleExists('config')); + } + +} diff --git a/core/tests/Drupal/KernelTests/Core/Extension/ProfileHandlerTest.php b/core/tests/Drupal/KernelTests/Core/Extension/ProfileHandlerTest.php index ebb20f6a00..92d553db9f 100644 --- a/core/tests/Drupal/KernelTests/Core/Extension/ProfileHandlerTest.php +++ b/core/tests/Drupal/KernelTests/Core/Extension/ProfileHandlerTest.php @@ -59,18 +59,34 @@ public function testGetProfileInfo() { $this->assertArrayHasKey('excluded_themes', $info['base profile']); $this->assertInternalType('array', $info['base profile']['excluded_themes']); $this->assertEmpty($info['base profile']['excluded_themes']); + + // Tests three levels profile inheritance. + $info = $profile_handler->getProfileInfo('testing_subsubprofile'); + $this->assertEquals($info['base profile']['name'], 'testing_inherited'); + $this->assertEquals($info['profile_list'], [ + 'testing' => 'testing', + 'testing_inherited' => 'testing_inherited', + 'testing_subsubprofile' => 'testing_subsubprofile', + ]); } /** * Tests getting profile dependency list. * - * @covers ::getProfiles + * @covers ::getProfileInheritance */ - public function testGetProfiles() { + public function testGetProfileInheritance() { $profile_handler = $this->container->get('profile_handler'); - $profiles = $profile_handler->getProfiles('testing_inherited'); + + $profiles = $profile_handler->getProfileInheritance('testing'); + $this->assertCount(1, $profiles); + + $profiles = $profile_handler->getProfileInheritance('testing_inherited'); $this->assertCount(2, $profiles); + $profiles = $profile_handler->getProfileInheritance('testing_subsubprofile'); + $this->assertCount(3, $profiles); + $first_profile = current($profiles); $this->assertEquals(get_class($first_profile), 'Drupal\Core\Extension\Extension'); $this->assertEquals($first_profile->getName(), 'testing'); @@ -82,6 +98,12 @@ public function testGetProfiles() { $this->assertEquals($second_profile->getName(), 'testing_inherited'); $this->assertEquals($second_profile->weight, 1001); $this->assertObjectHasAttribute('origin', $second_profile); + + $third_profile = next($profiles); + $this->assertEquals(get_class($third_profile), 'Drupal\Core\Extension\Extension'); + $this->assertEquals($third_profile->getName(), 'testing_subsubprofile'); + $this->assertEquals($third_profile->weight, 1002); + $this->assertObjectHasAttribute('origin', $third_profile); } /** @@ -95,21 +117,21 @@ public function testSelectDistribution() { $base_info = $profile_handler->getProfileInfo('minimal'); $profile_info = $profile_handler->getProfileInfo('testing_inherited'); - // Neither profile has distribution set + // Neither profile has distribution set. $distribution = $profile_handler->selectDistribution($profiles); $this->assertEmpty($distribution, 'No distribution should be selected'); - // Set base profile distribution + // Set base profile distribution. $base_info['distribution']['name'] = 'Minimal'; $profile_handler->setProfileInfo('minimal', $base_info); - // Base profile distribution should not be selected + // Base profile distribution should not be selected. $distribution = $profile_handler->selectDistribution($profiles); $this->assertEmpty($distribution, 'Base profile distribution should not be selected'); - // Set main profile distribution + // Set main profile distribution. $profile_info['distribution']['name'] = 'Testing Inherited'; $profile_handler->setProfileInfo('testing_inherited', $profile_info); - // Main profile distribution should be selected + // Main profile distribution should be selected. $distribution = $profile_handler->selectDistribution($profiles); $this->assertEquals($distribution, 'testing_inherited'); }