diff --git a/core/includes/install.inc b/core/includes/install.inc index 358b259..ab818ba 100644 --- a/core/includes/install.inc +++ b/core/includes/install.inc @@ -479,8 +479,6 @@ function drupal_install_config_directories() { ); // Rewrite settings.php, which also sets the value as global variable. drupal_rewrite_settings($settings); - - \Drupal::service('config.storage.active')->createStorage(); } // Ensure the config directories exist or can be created, and are writable. diff --git a/core/lib/Drupal/Core/Config/CachedStorage.php b/core/lib/Drupal/Core/Config/CachedStorage.php index f10b794..1ff4046 100644 --- a/core/lib/Drupal/Core/Config/CachedStorage.php +++ b/core/lib/Drupal/Core/Config/CachedStorage.php @@ -54,14 +54,6 @@ public function __construct(StorageInterface $storage, CacheBackendInterface $ca } /** - * {@inheritdoc} - */ - public function createStorage() { - $this->storage->createStorage(); - return $this; - } - - /** * Implements Drupal\Core\Config\StorageInterface::exists(). */ public function exists($name) { diff --git a/core/lib/Drupal/Core/Config/DatabaseStorage.php b/core/lib/Drupal/Core/Config/DatabaseStorage.php index a2ba289..ed0bd72 100644 --- a/core/lib/Drupal/Core/Config/DatabaseStorage.php +++ b/core/lib/Drupal/Core/Config/DatabaseStorage.php @@ -54,19 +54,6 @@ public function __construct(Connection $connection, $table, array $options = arr } /** - * {@inheritdoc} - */ - public function createStorage() { - try { - $this->connection->schema()->createTable($this->table, static::schemaDefinition()); - } - catch (\Exception $e) { - throw new StorageException($e->getMessage(), NULL, $e); - } - return $this; - } - - /** * Implements Drupal\Core\Config\StorageInterface::exists(). */ public function exists($name) { @@ -76,9 +63,8 @@ public function exists($name) { ), $this->options)->fetchField(); } catch (\Exception $e) { - // There are situations, like in the installer, where we may attempt a - // read without actually having the database available. In this case, - // catch the exception and just return FALSE so the caller can handle it. + // If we attempt a read without actually having the database or the table + // available, just return FALSE so the caller can handle it. return FALSE; } } @@ -95,9 +81,8 @@ public function read($name) { } } catch (\Exception $e) { - // There are situations, like in the installer, where we may attempt a - // read without actually having the database available. In this case, - // catch the exception and just return FALSE so the caller can handle it. + // If we attempt a read without actually having the database or the table + // available, just return FALSE so the caller can handle it. } return $data; } @@ -114,33 +99,80 @@ public function readMultiple(array $names) { } } catch (\Exception $e) { - // There are situations, like in the installer, where we may attempt a - // read without actually having the database available. In this case, - // catch the exception and just return an empty array so the caller can - // handle it if need be. + // If we attempt a read without actually having the database or the table + // available, just return an empty array so the caller can handle it. } return $list; } /** - * Implements Drupal\Core\Config\StorageInterface::write(). + * {@inheritdoc} + */ + public function write($name, array $data) { + $data = $this->encode($data); + try { + return $this->doWrite($name, $data); + } + catch (\Exception $e) { + // If there was an exception, try to create the table. + if ($this->ensureTableExists()) { + return $this->doWrite($name, $data); + } + // Some other failure that we can not recover from. + throw $e; + } + } + + /** + * Helper method so we can re-try a write. * - * @throws PDOException + * @param string $name + * The config name. + * @param string $data + * The config data, already dumped to a string. * - * @todo Ignore slave targets for data manipulation operations. + * @return bool */ - public function write($name, array $data) { + protected function doWrite($name, $data) { $options = array('return' => Database::RETURN_AFFECTED) + $this->options; return (bool) $this->connection->merge($this->table, $options) ->key('name', $name) - ->fields(array('data' => $this->encode($data))) + ->fields(array('data' => $data)) ->execute(); } /** + * Check if the config table exists and create it if not. + * + * @return bool + * TRUE if the table was created, FALSE otherwise. + * + * @throws \Drupal\Core\Config\StorageException + * If a database error occurs. + */ + protected function ensureTableExists() { + try { + if (!$this->connection->schema()->tableExists($this->table)) { + $this->connection->schema()->createTable($this->table, static::schemaDefinition()); + return TRUE; + } + } + // If another process has already created the config table, attempting to + // recreate it will throw an exception. In this case just catch the + // exception and do nothing. + catch (SchemaObjectExistsException $e) { + return TRUE; + } + catch (\Exception $e) { + throw new StorageException($e->getMessage(), NULL, $e); + } + return FALSE; + } + + /** * Defines the schema for the configuration table. */ - protected function schemaDefinition() { + protected static function schemaDefinition() { $schema = array( 'description' => 'The base table for configuration data.', 'fields' => array( diff --git a/core/lib/Drupal/Core/Config/FileStorage.php b/core/lib/Drupal/Core/Config/FileStorage.php index 26da8d2..d660169 100644 --- a/core/lib/Drupal/Core/Config/FileStorage.php +++ b/core/lib/Drupal/Core/Config/FileStorage.php @@ -69,10 +69,9 @@ public static function getFileExtension() { } /** - * {@inheritdoc} + * Check if the directory exists and create it if not. */ - public function createStorage() { - // @todo: Use this method during install. + protected function ensureStorage() { $success = file_prepare_directory($this->directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS); $success = $success && file_save_htaccess($this->directory, TRUE, TRUE); if (!$success) { @@ -118,22 +117,24 @@ public function readMultiple(array $names) { } /** - * Implements Drupal\Core\Config\StorageInterface::write(). - * - * @throws \Drupal\Core\Config\UnsupportedDataTypeConfigException - * @throws \Drupal\Core\Config\StorageException + * {@inheritdoc} */ public function write($name, array $data) { try { $data = $this->encode($data); } catch(DumpException $e) { - throw new UnsupportedDataTypeConfigException(String::format('Invalid data type for used in config: @name', array('@name' => $name))); + throw new StorageException(String::format('Invalid data type for used in config: @name', array('@name' => $name))); } $target = $this->getFilePath($name); $status = @file_put_contents($target, $data); if ($status === FALSE) { + // Try to make sure the directory exists and try witing again. + $this->ensureStorage(); + $status = @file_put_contents($target, $data); + } + if ($status === FALSE) { throw new StorageException('Failed to write configuration file: ' . $this->getFilePath($name)); } else { diff --git a/core/lib/Drupal/Core/Config/InstallStorage.php b/core/lib/Drupal/Core/Config/InstallStorage.php index 89d478c..124748a 100644 --- a/core/lib/Drupal/Core/Config/InstallStorage.php +++ b/core/lib/Drupal/Core/Config/InstallStorage.php @@ -65,13 +65,6 @@ public function getFilePath($name) { } /** - * {@inheritdoc} - */ - public function createStorage() { - return $this; - } - - /** * Overrides Drupal\Core\Config\FileStorage::write(). * * @throws \Drupal\Core\Config\StorageException diff --git a/core/lib/Drupal/Core/Config/NullStorage.php b/core/lib/Drupal/Core/Config/NullStorage.php index 5ab1fa8..2bf121d 100644 --- a/core/lib/Drupal/Core/Config/NullStorage.php +++ b/core/lib/Drupal/Core/Config/NullStorage.php @@ -24,13 +24,6 @@ class NullStorage implements StorageInterface { /** - * {@inheritdoc} - */ - public function createStorage() { - return $this; - } - - /** * Implements Drupal\Core\Config\StorageInterface::exists(). */ public function exists($name) { diff --git a/core/lib/Drupal/Core/Config/StorageInterface.php b/core/lib/Drupal/Core/Config/StorageInterface.php index 7d5e0fc..4e23761 100644 --- a/core/lib/Drupal/Core/Config/StorageInterface.php +++ b/core/lib/Drupal/Core/Config/StorageInterface.php @@ -16,16 +16,6 @@ interface StorageInterface { /** - * Creates the storage for this backend. - * - * @return $this - * - * @throws \Drupal\Core\Config\StorageException - * If the storage cannot be created. - */ - public function createStorage(); - - /** * Returns whether a configuration object exists. * * @param string $name @@ -70,6 +60,9 @@ public function readMultiple(array $names); * * @return bool * TRUE on success, FALSE in case of an error. + * + * @throws \Drupal\Core\Config\StorageException + * If the back-end storage does not exist and cannot be created. */ public function write($name, array $data); diff --git a/core/modules/config/lib/Drupal/config/Tests/Storage/ConfigStorageTestBase.php b/core/modules/config/lib/Drupal/config/Tests/Storage/ConfigStorageTestBase.php index 74df325..cef916b 100644 --- a/core/modules/config/lib/Drupal/config/Tests/Storage/ConfigStorageTestBase.php +++ b/core/modules/config/lib/Drupal/config/Tests/Storage/ConfigStorageTestBase.php @@ -115,15 +115,6 @@ function testCRUD() { $this->assertIdentical($result, TRUE); $this->assertIdentical($names, array()); - // Writing to a non-existing storage bin throws an exception. - try { - $this->invalidStorage->write($name, array('foo' => 'bar')); - $this->fail('Exception not thrown upon writing to a non-existing storage bin.'); - } - catch (\Exception $e) { - $class = get_class($e); - $this->pass($class . ' thrown upon writing to a non-existing storage bin.'); - } // Deleting from a non-existing storage bin throws an exception. try { @@ -153,6 +144,10 @@ function testCRUD() { $this->pass($class . ' thrown upon renaming a nonexistent storage bin.'); } + // Writing to a non-existing storage bin creates the bin. + $this->invalidStorage->write($name, array('foo' => 'bar')); + $result = $this->invalidStorage->read($name); + $this->assertIdentical($result, array('foo' => 'bar')); } /** diff --git a/core/modules/config/lib/Drupal/config/Tests/Storage/DatabaseStorageTest.php b/core/modules/config/lib/Drupal/config/Tests/Storage/DatabaseStorageTest.php index beb24da..eba9873 100644 --- a/core/modules/config/lib/Drupal/config/Tests/Storage/DatabaseStorageTest.php +++ b/core/modules/config/lib/Drupal/config/Tests/Storage/DatabaseStorageTest.php @@ -25,7 +25,6 @@ function setUp() { parent::setUp(); $this->storage = new DatabaseStorage($this->container->get('database'), 'config'); - $this->storage->createStorage(); $this->invalidStorage = new DatabaseStorage($this->container->get('database'), 'invalid'); // ::listAll() verifications require other configuration data to exist. diff --git a/core/modules/config/lib/Drupal/config/Tests/Storage/FileStorageTest.php b/core/modules/config/lib/Drupal/config/Tests/Storage/FileStorageTest.php index 4331e99..bcd49989 100644 --- a/core/modules/config/lib/Drupal/config/Tests/Storage/FileStorageTest.php +++ b/core/modules/config/lib/Drupal/config/Tests/Storage/FileStorageTest.php @@ -25,7 +25,6 @@ public static function getInfo() { function setUp() { parent::setUp(); $this->storage = new FileStorage($this->configDirectories[CONFIG_ACTIVE_DIRECTORY]); - $this->storage->createStorage(); $this->invalidStorage = new FileStorage($this->configDirectories[CONFIG_ACTIVE_DIRECTORY] . '/nonexisting'); // FileStorage::listAll() requires other configuration data to exist. diff --git a/core/modules/simpletest/lib/Drupal/simpletest/DrupalUnitTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/DrupalUnitTestBase.php index e175f1e..b6e4ee2 100644 --- a/core/modules/simpletest/lib/Drupal/simpletest/DrupalUnitTestBase.php +++ b/core/modules/simpletest/lib/Drupal/simpletest/DrupalUnitTestBase.php @@ -138,9 +138,6 @@ protected function setUp() { \Drupal::state()->set('system.module.files', $this->moduleFiles); \Drupal::state()->set('system.theme.files', $this->themeFiles); - // Create the active configuration storage (required to boot DrupalKernel). - $this->container->get('config.storage.active')->createStorage(); - // Bootstrap the kernel. // No need to dump it; this test runs in-memory. $this->kernel = new DrupalKernel('unit_testing', drupal_classloader(), FALSE);