diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index 2294d47..ec12097 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -151,10 +151,11 @@ function config_get_config_directory($type) {
}
if (!empty($config_directories[$type])) {
return $config_directories[$type];
}
+ // @todo https://www.drupal.org/node/2696103 Throw a more specific exception.
throw new \Exception("The configuration directory type '$type' does not exist");
}
/**
* Returns and optionally sets the filename for a system resource.
diff --git a/core/includes/file.inc b/core/includes/file.inc
index 3e5eb8c..b38efb8 100644
--- a/core/includes/file.inc
+++ b/core/includes/file.inc
@@ -330,11 +330,23 @@ function file_ensure_htaccess() {
$private_path = PrivateStream::basePath();
if (!empty($private_path)) {
file_save_htaccess('private://', TRUE);
}
file_save_htaccess('temporary://', TRUE);
- file_save_htaccess(config_get_config_directory(CONFIG_SYNC_DIRECTORY), TRUE);
+
+ // If a staging directory exists then it should contain a .htaccess file.
+ // @todo https://www.drupal.org/node/2696103 catch a more specific exception
+ // and simplify this code.
+ try {
+ $staging = config_get_config_directory(CONFIG_SYNC_DIRECTORY);
+ }
+ catch (\Exception $e) {
+ $staging = FALSE;
+ }
+ if ($staging) {
+ file_save_htaccess($staging, TRUE);
+ }
}
/**
* Creates a .htaccess file in the given directory.
*
diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc
index 8dd191c..57a2ef5 100644
--- a/core/includes/install.core.inc
+++ b/core/includes/install.core.inc
@@ -2071,11 +2071,11 @@ function install_check_requirements($install_state) {
// If the $file is not writable, throw an error.
if (!$writable) {
$requirements["$file file writeable"] = array(
'title' => $default_file_info['title'],
'value' => t('The %file is not writable.', array('%file' => $default_file_info['title'])),
- 'severity' => REQUIREMENT_ERROR,
+ 'severity' => REQUIREMENT_WARNING,
'description' => t('The @drupal installer requires write permissions to %file during the installation process. The webhosting issues documentation section offers help on this and other topics.', array(
'@drupal' => drupal_install_profile_distribution_name(),
'%file' => $file,
':handbook_url' => 'https://www.drupal.org/server-permissions'
)),
diff --git a/core/modules/config/config.install b/core/modules/config/config.install
new file mode 100644
index 0000000..c971ae6
--- /dev/null
+++ b/core/modules/config/config.install
@@ -0,0 +1,32 @@
+ t('Configuration directory: %type', ['%type' => CONFIG_SYNC_DIRECTORY]),
+ 'description' => t('The directory %directory is not writable.', ['%directory' => $directory]),
+ 'severity' => REQUIREMENT_WARNING,
+ ];
+ }
+ return $requirements;
+}
diff --git a/core/modules/config/src/Form/ConfigImportForm.php b/core/modules/config/src/Form/ConfigImportForm.php
index f95b7a5..1d651d8 100644
--- a/core/modules/config/src/Form/ConfigImportForm.php
+++ b/core/modules/config/src/Form/ConfigImportForm.php
@@ -48,19 +48,25 @@ public function getFormId() {
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
+ $directory = config_get_config_directory(CONFIG_SYNC_DIRECTORY);
+ $directory_is_writable = is_writable($directory);
+ if (!$directory_is_writable) {
+ drupal_set_message($this->t('The directory %directory is not writable.', ['%directory' => $directory]), 'error');
+ }
$form['import_tarball'] = array(
'#type' => 'file',
'#title' => $this->t('Configuration archive'),
'#description' => $this->t('Allowed types: @extensions.', array('@extensions' => 'tar.gz tgz tar.bz2')),
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => $this->t('Upload'),
+ '#disabled' => !$directory_is_writable,
);
return $form;
}
/**
diff --git a/core/modules/config/src/Tests/ConfigImportUploadTest.php b/core/modules/config/src/Tests/ConfigImportUploadTest.php
index 445ca9f..9836d77 100644
--- a/core/modules/config/src/Tests/ConfigImportUploadTest.php
+++ b/core/modules/config/src/Tests/ConfigImportUploadTest.php
@@ -43,8 +43,18 @@ function testImport() {
// Attempt to upload a non-tar file.
$text_file = current($this->drupalGetTestFiles('text'));
$edit = array('files[import_tarball]' => drupal_realpath($text_file->uri));
$this->drupalPostForm('admin/config/development/configuration/full/import', $edit, t('Upload'));
$this->assertText(t('Could not extract the contents of the tar file'));
+
+ // Make the sync directory read-only.
+ $directory = config_get_config_directory(CONFIG_SYNC_DIRECTORY);
+ \Drupal::service('file_system')->chmod($directory, 0555);
+ $this->drupalGet('admin/config/development/configuration/full/import');
+ $this->assertRaw(t('The directory %directory is not writable.', ['%directory' => $directory]));
+ // Ensure submit button for \Drupal\config\Form\ConfigImportForm is
+ // disabled.
+ $submit_is_disabled = $this->cssSelect('form.config-import-form input[type="submit"]:disabled');
+ $this->assertTrue(count($submit_is_disabled) === 1, 'The submit button is disabled.');
}
}
diff --git a/core/modules/config/src/Tests/ConfigInstallWebTest.php b/core/modules/config/src/Tests/ConfigInstallWebTest.php
index 4b18a4c..fc6cee4 100644
--- a/core/modules/config/src/Tests/ConfigInstallWebTest.php
+++ b/core/modules/config/src/Tests/ConfigInstallWebTest.php
@@ -24,11 +24,11 @@ class ConfigInstallWebTest extends WebTestBase {
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
- $this->adminUser = $this->drupalCreateUser(array('administer modules', 'administer themes'));
+ $this->adminUser = $this->drupalCreateUser(array('administer modules', 'administer themes', 'administer site configuration'));
// Ensure the global variable being asserted by this test does not exist;
// a previous test executed in this request/process might have set it.
unset($GLOBALS['hook_config_test']);
}
@@ -186,6 +186,24 @@ public function testUnmetDependenciesInstall() {
$this->drupalPostForm('admin/modules', array('modules[Testing][config_install_dependency_test][enable]' => TRUE), t('Install'));
$this->rebuildContainer();
$this->assertTrue(entity_load('config_test', 'other_module_test_with_dependency'), 'The config_test.dynamic.other_module_test_with_dependency configuration has been created during install.');
}
+ /**
+ * Tests config_requirements().
+ */
+ public function testConfigModuleRequirements() {
+ $this->drupalLogin($this->adminUser);
+ $this->drupalPostForm('admin/modules', array('modules[Core][config][enable]' => TRUE), t('Install'));
+
+ $directory = config_get_config_directory(CONFIG_SYNC_DIRECTORY);
+ file_unmanaged_delete_recursive($directory);
+ $this->drupalGet('/admin/reports/status');
+ $this->assertRaw(t('The directory %directory does not exist.', array('%directory' => $directory)));
+
+ file_prepare_directory($directory, FILE_CREATE_DIRECTORY);
+ \Drupal::service('file_system')->chmod($directory, 0555);
+ $this->drupalGet('/admin/reports/status');
+ $this->assertRaw(t('The directory %directory is not writable.', ['%directory' => $directory]));
+ }
+
}
diff --git a/core/modules/system/src/Tests/System/StatusTest.php b/core/modules/system/src/Tests/System/StatusTest.php
index 525b079..c170316 100644
--- a/core/modules/system/src/Tests/System/StatusTest.php
+++ b/core/modules/system/src/Tests/System/StatusTest.php
@@ -22,10 +22,20 @@ class StatusTest extends WebTestBase {
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
+ // Unset the sync directory in settings.php to trigger $config_directories
+ // error.
+ $settings['config_directories'] = array(
+ CONFIG_SYNC_DIRECTORY => (object) array(
+ 'value' => '',
+ 'required' => TRUE,
+ ),
+ );
+ $this->writeSettings($settings);
+
$admin_user = $this->drupalCreateUser(array(
'administer site configuration',
));
$this->drupalLogin($admin_user);
}
@@ -58,10 +68,13 @@ public function testStatusPage() {
}
// If a module is fully installed no pending updates exists.
$this->assertNoText(t('Out of date'));
+ // The global $config_directories is not properly formed.
+ $this->assertRaw(t('Your %file file must define the $config_directories variable as an array containing the names of directories in which configuration files can be found. It must contain a %sync_key key.', array('%file' => $this->siteDirectory . '/settings.php', '%sync_key' => CONFIG_SYNC_DIRECTORY)));
+
// Set the schema version of update_test_postupdate to a lower version, so
// update_test_postupdate_update_8001() needs to be executed.
drupal_set_installed_schema_version('update_test_postupdate', 8000);
$this->drupalGet('admin/reports/status');
$this->assertText(t('Out of date'));
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index cdaeba6..effe9e3 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -547,19 +547,26 @@ function system_requirements($phase) {
// Check the config directory if it is defined in settings.php. If it isn't
// defined, the installer will create a valid config directory later, but
// during runtime we must always display an error.
if (!empty($GLOBALS['config_directories'])) {
- foreach ($GLOBALS['config_directories'] as $type => $directory) {
- $directories[] = config_get_config_directory($type);
+ foreach (array_keys(array_filter($GLOBALS['config_directories'])) as $type) {
+ $directory = config_get_config_directory($type);
+ if (!is_dir($directory)) {
+ $requirements['config directory ' . $type] = array(
+ 'title' => t('Configuration directory: %type', ['%type' => $type]),
+ 'description' => t('The directory %directory does not exist.', array('%directory' => $directory)),
+ 'severity' => REQUIREMENT_ERROR,
+ );
+ }
}
}
- elseif ($phase != 'install') {
+ if ($phase != 'install' && (empty($GLOBALS['config_directories']) || empty($GLOBALS['config_directories'][CONFIG_SYNC_DIRECTORY]) )) {
$requirements['config directories'] = array(
'title' => t('Configuration directories'),
'value' => t('Not present'),
- 'description' => t('Your %file file must define the $config_directories variable as an array containing the name of a directories in which configuration files can be written.', array('%file' => $site_path . '/settings.php')),
+ 'description' => t('Your %file file must define the $config_directories variable as an array containing the names of directories in which configuration files can be found. It must contain a %sync_key key.', array('%file' => $site_path . '/settings.php', '%sync_key' => CONFIG_SYNC_DIRECTORY)),
'severity' => REQUIREMENT_ERROR,
);
}
$requirements['file system'] = array(
@@ -611,11 +618,11 @@ function system_requirements($phase) {
}
else {
// This function can be called before the config_cache table has been
// created.
if ($phase == 'install' || file_default_scheme() == 'public') {
- $requirements['file system']['value'] = t('Writable (public download method)');
+ //$requirements['file system']['value'] = t('Writable (public download method)');
}
else {
$requirements['file system']['value'] = t('Writable (private download method)');
}
}