Commit 16726375 authored by catch's avatar catch
Browse files

Issue #2975328 by alexpott, Gábor Hojtsy, borisson_: Install profile in...

Issue #2975328 by alexpott, Gábor Hojtsy, borisson_: Install profile in settings.php and mismatch check makes re-installs of Drupal hard
parent 646584b3
...@@ -14,7 +14,6 @@ ...@@ -14,7 +14,6 @@
use Drupal\Core\Logger\RfcLogLevel; use Drupal\Core\Logger\RfcLogLevel;
use Drupal\Core\Test\TestDatabase; use Drupal\Core\Test\TestDatabase;
use Drupal\Core\Session\AccountInterface; use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Site\Settings;
use Drupal\Core\Utility\Error; use Drupal\Core\Utility\Error;
use Drupal\Core\StringTranslation\TranslatableMarkup; use Drupal\Core\StringTranslation\TranslatableMarkup;
...@@ -797,12 +796,6 @@ function drupal_get_profile() { ...@@ -797,12 +796,6 @@ function drupal_get_profile() {
else { else {
$profile = BootstrapConfigStorageFactory::getDatabaseStorage()->read('core.extension')['profile']; $profile = BootstrapConfigStorageFactory::getDatabaseStorage()->read('core.extension')['profile'];
} }
// A BC layer just in in case this only exists in Settings. Introduced in
// Drupal 8.3.x and will be removed before Drupal 9.0.0.
if (empty($profile)) {
$profile = Settings::get('install_profile');
}
} }
return $profile; return $profile;
......
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
use Drupal\Core\Form\FormState; use Drupal\Core\Form\FormState;
use Drupal\Core\Installer\Exception\AlreadyInstalledException; use Drupal\Core\Installer\Exception\AlreadyInstalledException;
use Drupal\Core\Installer\Exception\InstallerException; use Drupal\Core\Installer\Exception\InstallerException;
use Drupal\Core\Installer\Exception\InstallProfileMismatchException;
use Drupal\Core\Installer\Exception\NoProfilesException; use Drupal\Core\Installer\Exception\NoProfilesException;
use Drupal\Core\Installer\InstallerKernel; use Drupal\Core\Installer\InstallerKernel;
use Drupal\Core\Language\Language; use Drupal\Core\Language\Language;
...@@ -2284,16 +2283,16 @@ function install_display_requirements($install_state, $requirements) { ...@@ -2284,16 +2283,16 @@ function install_display_requirements($install_state, $requirements) {
* *
* @see _install_select_profile() * @see _install_select_profile()
* *
* @throws \Drupal\Core\Installer\Exception\InstallProfileMismatchException
*
* @deprecated in Drupal 8.3.0 and will be removed before Drupal 9.0.0. The * @deprecated in Drupal 8.3.0 and will be removed before Drupal 9.0.0. The
* install profile is written to core.extension. * install profile is written to core.extension.
*/ */
function install_write_profile($install_state) { function install_write_profile($install_state) {
// Only need to write to settings.php if it is possible. The primary storage // Only write the install profile to settings.php if already exists. The value
// for the install profile is the core.extension configuration. // from settings.php is never used but drupal_rewrite_settings() does not
// support removing a setting. If the value in configuration and settings.php
// don't match there will be a warning on the status report.
$settings_path = \Drupal::service('site.path') . '/settings.php'; $settings_path = \Drupal::service('site.path') . '/settings.php';
if (is_writable($settings_path)) { if (is_writable($settings_path) && array_key_exists('install_profile', Settings::getAll())) {
// Remember the profile which was used. // Remember the profile which was used.
$settings['settings']['install_profile'] = (object) [ $settings['settings']['install_profile'] = (object) [
'value' => $install_state['parameters']['profile'], 'value' => $install_state['parameters']['profile'],
...@@ -2301,9 +2300,6 @@ function install_write_profile($install_state) { ...@@ -2301,9 +2300,6 @@ function install_write_profile($install_state) {
]; ];
drupal_rewrite_settings($settings); drupal_rewrite_settings($settings);
} }
elseif (($settings_profile = Settings::get('install_profile')) && $settings_profile !== $install_state['parameters']['profile']) {
throw new InstallProfileMismatchException($install_state['parameters']['profile'], $settings_profile, $settings_path, \Drupal::translation());
}
} }
/** /**
......
...@@ -1604,13 +1604,14 @@ protected function addServiceFiles(array $service_yamls) { ...@@ -1604,13 +1604,14 @@ protected function addServiceFiles(array $service_yamls) {
*/ */
protected function getInstallProfile() { protected function getInstallProfile() {
$config = $this->getConfigStorage()->read('core.extension'); $config = $this->getConfigStorage()->read('core.extension');
if (!empty($config['profile'])) { if (isset($config['profile'])) {
$install_profile = $config['profile']; $install_profile = $config['profile'];
} }
// @todo https://www.drupal.org/node/2831065 remove the BC layer. // @todo https://www.drupal.org/node/2831065 remove the BC layer.
else { else {
// If system_update_8300() has not yet run fallback to using settings. // If system_update_8300() has not yet run fallback to using settings.
$install_profile = Settings::get('install_profile'); $settings = Settings::getAll();
$install_profile = isset($settings['install_profile']) ? $settings['install_profile'] : NULL;
} }
// Normalize an empty string to a NULL value. // Normalize an empty string to a NULL value.
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
use Drupal\Core\StringTranslation\TranslationInterface; use Drupal\Core\StringTranslation\TranslationInterface;
@trigger_error(__NAMESPACE__ . '/InstallProfileMismatchException is deprecated in Drupal 8.6.0 and will be removed before Drupal 9. See https://www.drupal.org/node/2538996', E_USER_DEPRECATED);
/** /**
* Exception thrown if settings.php cannot be written and the chosen profile does not match. * Exception thrown if settings.php cannot be written and the chosen profile does not match.
*/ */
......
...@@ -225,11 +225,6 @@ public function submitForm(array &$form, FormStateInterface $form_state) { ...@@ -225,11 +225,6 @@ public function submitForm(array &$form, FormStateInterface $form_state) {
'value' => Crypt::randomBytesBase64(55), 'value' => Crypt::randomBytesBase64(55),
'required' => TRUE, 'required' => TRUE,
]; ];
// Remember the profile which was used.
$settings['settings']['install_profile'] = (object) [
'value' => $install_state['parameters']['profile'],
'required' => TRUE,
];
drupal_rewrite_settings($settings); drupal_rewrite_settings($settings);
......
...@@ -84,6 +84,9 @@ public function __sleep() { ...@@ -84,6 +84,9 @@ public function __sleep() {
* The value of the setting, the provided default if not set. * The value of the setting, the provided default if not set.
*/ */
public static function get($name, $default = NULL) { public static function get($name, $default = NULL) {
if ($name === 'install_profile' && isset(self::$instance->storage[$name])) {
@trigger_error('To access the install profile in Drupal 8 use \Drupal::installProfile() or inject the install_profile container parameter into your service. See https://www.drupal.org/node/2538996', E_USER_DEPRECATED);
}
return isset(self::$instance->storage[$name]) ? self::$instance->storage[$name] : $default; return isset(self::$instance->storage[$name]) ? self::$instance->storage[$name] : $default;
} }
......
...@@ -1015,6 +1015,21 @@ function system_requirements($phase) { ...@@ -1015,6 +1015,21 @@ function system_requirements($phase) {
]; ];
} }
} }
if ($phase === 'runtime') {
$settings = Settings::getAll();
if (array_key_exists('install_profile', $settings)) {
// The following message is only informational because not all site owners
// have access to edit their settings.php as it may be controlled by their
// hosting provider.
$requirements['install_profile_in_settings'] = [
'title' => t('Install profile in settings'),
'value' => t("Drupal 8 no longer uses the \$settings['install_profile'] value in settings.php and it can be removed."),
'severity' => REQUIREMENT_INFO,
];
}
}
return $requirements; return $requirements;
} }
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
* Tests system_update_8300(). * Tests system_update_8300().
* *
* @group Update * @group Update
* @group legacy
*/ */
class InstallProfileSystemInstall8300Test extends UpdatePathTestBase { class InstallProfileSystemInstall8300Test extends UpdatePathTestBase {
...@@ -23,6 +24,8 @@ protected function setDatabaseDumpFiles() { ...@@ -23,6 +24,8 @@ protected function setDatabaseDumpFiles() {
/** /**
* Ensures that the system_update_8300() runs as expected. * Ensures that the system_update_8300() runs as expected.
*
* @expectedDeprecation To access the install profile in Drupal 8 use \Drupal::installProfile() or inject the install_profile container parameter into your service. See https://www.drupal.org/node/2538996
*/ */
public function testUpdate() { public function testUpdate() {
// Ensure the BC layers work and settings.php and configuration is in the // Ensure the BC layers work and settings.php and configuration is in the
......
...@@ -179,7 +179,7 @@ public function testDependencyResolution() { ...@@ -179,7 +179,7 @@ public function testDependencyResolution() {
public function testUninstallProfileDependencyBC() { public function testUninstallProfileDependencyBC() {
$profile = 'testing_install_profile_dependencies_bc'; $profile = 'testing_install_profile_dependencies_bc';
$dependency = 'dblog'; $dependency = 'dblog';
$this->setSetting('install_profile', $profile); $this->setInstallProfile($profile);
// Prime the drupal_get_filename() static cache with the location of the // Prime the drupal_get_filename() static cache with the location of the
// testing profile as it is not the currently active profile and we don't // testing profile as it is not the currently active profile and we don't
// yet have any cached way to retrieve its location. // yet have any cached way to retrieve its location.
...@@ -213,7 +213,7 @@ public function testUninstallProfileDependency() { ...@@ -213,7 +213,7 @@ public function testUninstallProfileDependency() {
$profile = 'testing_install_profile_dependencies'; $profile = 'testing_install_profile_dependencies';
$dependency = 'dblog'; $dependency = 'dblog';
$non_dependency = 'ban'; $non_dependency = 'ban';
$this->setSetting('install_profile', $profile); $this->setInstallProfile($profile);
// Prime the drupal_get_filename() static cache with the location of the // Prime the drupal_get_filename() static cache with the location of the
// testing_install_profile_dependencies profile as it is not the currently // testing_install_profile_dependencies profile as it is not the currently
// active profile and we don't yet have any cached way to retrieve its // active profile and we don't yet have any cached way to retrieve its
...@@ -252,7 +252,7 @@ public function testProfileAllDependencies() { ...@@ -252,7 +252,7 @@ public function testProfileAllDependencies() {
$profile = 'testing_install_profile_all_dependencies'; $profile = 'testing_install_profile_all_dependencies';
$dependencies = ['dblog', 'ban']; $dependencies = ['dblog', 'ban'];
$this->setSetting('install_profile', $profile); $this->setInstallProfile($profile);
// Prime the drupal_get_filename() static cache with the location of the // Prime the drupal_get_filename() static cache with the location of the
// testing_install_profile_dependencies profile as it is not the currently // testing_install_profile_dependencies profile as it is not the currently
// active profile and we don't yet have any cached way to retrieve its // active profile and we don't yet have any cached way to retrieve its
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
namespace Drupal\Tests\demo_umami_content\Functional; namespace Drupal\Tests\demo_umami_content\Functional;
use Drupal\Core\Site\Settings;
use Drupal\Tests\BrowserTestBase; use Drupal\Tests\BrowserTestBase;
/** /**
...@@ -18,7 +17,7 @@ class DefaultContentFilesAccessTest extends BrowserTestBase { ...@@ -18,7 +17,7 @@ class DefaultContentFilesAccessTest extends BrowserTestBase {
public function testAccessDeniedToFiles() { public function testAccessDeniedToFiles() {
// The demo_umami profile should not be used because we want to ensure that // The demo_umami profile should not be used because we want to ensure that
// if you install another profile these files are not available. // if you install another profile these files are not available.
$this->assertNotSame('demo_umami', Settings::get('install_profile')); $this->assertNotSame('demo_umami', \Drupal::installProfile());
$files_to_test = [ $files_to_test = [
'images/chocolate-brownie-umami.jpg', 'images/chocolate-brownie-umami.jpg',
......
...@@ -119,7 +119,7 @@ public function testInstalled() { ...@@ -119,7 +119,7 @@ public function testInstalled() {
// Confirm that Drupal recognizes this distribution as the current profile. // Confirm that Drupal recognizes this distribution as the current profile.
$this->assertEqual(\Drupal::installProfile(), 'mydistro'); $this->assertEqual(\Drupal::installProfile(), 'mydistro');
$this->assertNull(Settings::get('install_profile'), 'The install profile has not been written to settings.php.'); $this->assertArrayNotHasKey('install_profile', Settings::getAll(), 'The install profile has not been written to settings.php.');
$this->assertEqual($this->config('core.extension')->get('profile'), 'mydistro', 'The install profile has been written to core.extension configuration.'); $this->assertEqual($this->config('core.extension')->get('profile'), 'mydistro', 'The install profile has been written to core.extension configuration.');
$this->rebuildContainer(); $this->rebuildContainer();
......
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
namespace Drupal\FunctionalTests\Installer; namespace Drupal\FunctionalTests\Installer;
use Drupal\Core\Serialization\Yaml; use Drupal\Core\Serialization\Yaml;
use Drupal\Core\Site\Settings;
/** /**
* Tests distribution profile support. * Tests distribution profile support.
...@@ -74,7 +73,6 @@ public function testInstalled() { ...@@ -74,7 +73,6 @@ public function testInstalled() {
// Confirm that Drupal recognizes this distribution as the current profile. // Confirm that Drupal recognizes this distribution as the current profile.
$this->assertEqual(\Drupal::installProfile(), 'mydistro'); $this->assertEqual(\Drupal::installProfile(), 'mydistro');
$this->assertEqual(Settings::get('install_profile'), 'mydistro', 'The install profile has been written to settings.php.');
$this->assertEqual($this->config('core.extension')->get('profile'), 'mydistro', 'The install profile has been written to core.extension configuration.'); $this->assertEqual($this->config('core.extension')->get('profile'), 'mydistro', 'The install profile has been written to core.extension configuration.');
} }
......
...@@ -8,9 +8,10 @@ ...@@ -8,9 +8,10 @@
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
/** /**
* Tests the installer with an existing settings file but no install profile. * Tests install with existing settings.php and a mismatching install profile.
* *
* @group Installer * @group Installer
* @group legacy
*/ */
class InstallerExistingSettingsMismatchProfileTest extends InstallerTestBase { class InstallerExistingSettingsMismatchProfileTest extends InstallerTestBase {
...@@ -88,6 +89,8 @@ protected function setUpSettings() { ...@@ -88,6 +89,8 @@ protected function setUpSettings() {
/** /**
* Verifies that installation succeeded. * Verifies that installation succeeded.
*
* @expectedDeprecation To access the install profile in Drupal 8 use \Drupal::installProfile() or inject the install_profile container parameter into your service. See https://www.drupal.org/node/2538996
*/ */
public function testInstaller() { public function testInstaller() {
$this->assertUrl('user/1'); $this->assertUrl('user/1');
......
...@@ -4,14 +4,16 @@ ...@@ -4,14 +4,16 @@
use Drupal\Core\DrupalKernel; use Drupal\Core\DrupalKernel;
use Drupal\Core\Database\Database; use Drupal\Core\Database\Database;
use Drupal\Core\Site\Settings;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
/** /**
* Tests installer breaks with a profile mismatch and a read-only settings.php. * Tests installer breaks with a profile mismatch and a read-only settings.php.
* *
* @group Installer * @group Installer
* @group legacy
*/ */
class InstallerExistingSettingsMismatchProfileBrokenTest extends InstallerTestBase { class InstallerExistingSettingsReadOnlyMismatchProfileTest extends InstallerTestBase {
/** /**
* {@inheritdoc} * {@inheritdoc}
...@@ -91,16 +93,18 @@ protected function setUpSettings() { ...@@ -91,16 +93,18 @@ protected function setUpSettings() {
// already. // already.
} }
protected function setUpSite() {
// This step should not appear, since settings.php could not be written.
}
/** /**
* Verifies that installation did not succeed. * Verifies that installation succeeded.
*
* @expectedDeprecation To access the install profile in Drupal 8 use \Drupal::installProfile() or inject the install_profile container parameter into your service. See https://www.drupal.org/node/2538996
*/ */
public function testBrokenInstaller() { public function testInstalled() {
$this->assertTitle('Install profile mismatch | Drupal'); $this->initBrowserOutputFile();
$this->assertText("The selected profile testing does not match the install_profile setting, which is minimal. Cannot write updated setting to {$this->siteDirectory}/settings.php."); $this->htmlOutput(NULL);
$this->assertEquals('testing', \Drupal::installProfile());
$this->assertEquals('minimal', Settings::get('install_profile'));
$this->drupalGet('admin/reports/status');
$this->assertSession()->pageTextContains("Drupal 8 no longer uses the \$settings['install_profile'] value in settings.php and it can be removed.");
} }
} }
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
namespace Drupal\FunctionalTests\Installer; namespace Drupal\FunctionalTests\Installer;
use Drupal\Core\Site\Settings;
use Drupal\Core\Database\Database; use Drupal\Core\Database\Database;
use Drupal\Core\DrupalKernel; use Drupal\Core\DrupalKernel;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
...@@ -29,13 +28,6 @@ protected function prepareEnvironment() { ...@@ -29,13 +28,6 @@ protected function prepareEnvironment() {
'required' => TRUE, 'required' => TRUE,
]; ];
// During interactive install we'll change this to a different profile and
// this test will ensure that the new value is written to settings.php.
$this->settings['settings']['install_profile'] = (object) [
'value' => 'minimal',
'required' => TRUE,
];
// Pre-configure database credentials. // Pre-configure database credentials.
$connection_info = Database::getConnectionInfo(); $connection_info = Database::getConnectionInfo();
unset($connection_info['default']['pdo']); unset($connection_info['default']['pdo']);
...@@ -73,8 +65,7 @@ protected function setUpSettings() { ...@@ -73,8 +65,7 @@ protected function setUpSettings() {
public function testInstaller() { public function testInstaller() {
$this->assertUrl('user/1'); $this->assertUrl('user/1');
$this->assertResponse(200); $this->assertResponse(200);
$this->assertEqual('testing', \Drupal::installProfile(), 'Profile was changed from minimal to testing during interactive install.'); $this->assertEqual('testing', \Drupal::installProfile());
$this->assertEqual('testing', Settings::get('install_profile'), 'Profile was correctly changed to testing in Settings.php');
} }
} }
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
namespace Drupal\FunctionalTests\Installer; namespace Drupal\FunctionalTests\Installer;
use Drupal\Component\Serialization\Yaml; use Drupal\Component\Serialization\Yaml;
use Drupal\Core\Site\Settings;
/** /**
* Tests multiple distribution profile support. * Tests multiple distribution profile support.
...@@ -78,7 +77,6 @@ public function testInstalled() { ...@@ -78,7 +77,6 @@ public function testInstalled() {
// Confirm that Drupal recognizes this distribution as the current profile. // Confirm that Drupal recognizes this distribution as the current profile.
$this->assertEqual(\Drupal::installProfile(), 'distribution_one'); $this->assertEqual(\Drupal::installProfile(), 'distribution_one');
$this->assertEqual(Settings::get('install_profile'), 'distribution_one', 'The install profile has been written to settings.php.');
$this->assertEqual($this->config('core.extension')->get('profile'), 'distribution_one', 'The install profile has been written to core.extension configuration.'); $this->assertEqual($this->config('core.extension')->get('profile'), 'distribution_one', 'The install profile has been written to core.extension configuration.');
$this->rebuildContainer(); $this->rebuildContainer();
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
namespace Drupal\KernelTests\Core\Extension; namespace Drupal\KernelTests\Core\Extension;
use Drupal\Core\Site\Settings;
use Drupal\KernelTests\KernelTestBase; use Drupal\KernelTests\KernelTestBase;
/** /**
...@@ -15,12 +14,9 @@ class ModuleExtensionListTest extends KernelTestBase { ...@@ -15,12 +14,9 @@ class ModuleExtensionListTest extends KernelTestBase {
* @covers ::getList * @covers ::getList
*/ */
public function testGetlist() { public function testGetlist() {
$settings = Settings::getAll();
$settings['install_profile'] = 'testing';
new Settings($settings);
\Drupal::configFactory()->getEditable('core.extension') \Drupal::configFactory()->getEditable('core.extension')
->set('module.testing', 1000) ->set('module.testing', 1000)
->set('profile', 'testing')
->save(); ->save();
// The installation profile is provided by a container parameter. // The installation profile is provided by a container parameter.
......
...@@ -934,11 +934,32 @@ protected function render(array &$elements) { ...@@ -934,11 +934,32 @@ protected function render(array &$elements) {
* \Drupal\Core\Site\Settings::get() to perform custom merges. * \Drupal\Core\Site\Settings::get() to perform custom merges.
*/ */
protected function setSetting($name, $value) { protected function setSetting($name, $value) {
if ($name === 'install_profile') {
@trigger_error('Use \Drupal\KernelTests\KernelTestBase::setInstallProfile() to set the install profile in kernel tests. See https://www.drupal.org/node/2538996', E_USER_DEPRECATED);
$this->setInstallProfile($value);
}
$settings = Settings::getInstance() ? Settings::getAll() : []; $settings = Settings::getInstance() ? Settings::getAll() : [];
$settings[$name] = $value; $settings[$name] = $value;
new Settings($settings); new Settings($settings);
} }
/**
* Sets the install profile and rebuilds the container to update it.
*
* @param string $profile
* The install profile to set.
*/
protected function setInstallProfile($profile) {
$this->container->get('config.factory')
->getEditable('core.extension')
->set('profile', $profile)
->save();
// The installation profile is provided by a container parameter. Saving
// the configuration doesn't automatically trigger invalidation
$this->container->get('kernel')->rebuildContainer();
}
/** /**
* Stops test execution. * Stops test execution.
*/ */
......
...@@ -263,23 +263,6 @@ ...@@ -263,23 +263,6 @@
* @see \Drupal\Core\Site\Settings::get() * @see \Drupal\Core\Site\Settings::get()
*/ */
/**
* The active installation profile.
*
* Changing this after installation is not recommended as it changes which
* directories are scanned during extension discovery. If this is set prior to
* installation this value will be rewritten according to the profile selected
* by the user.
*
* @see install_select_profile()