diff -u b/core/lib/Drupal/Core/Config/FileStorage.php b/core/lib/Drupal/Core/Config/FileStorage.php --- b/core/lib/Drupal/Core/Config/FileStorage.php +++ b/core/lib/Drupal/Core/Config/FileStorage.php @@ -163,16 +163,7 @@ } return FALSE; } - $success = drupal_unlink($this->getFilePath($name)); - - // If a collection is now empty remove the directory. - if ($success && $this->collection != StorageInterface::DEFAULT_COLLECTION) { - $names = $this->listAll(); - if (empty($names)) { - drupal_rmdir($this->getCollectionDirectory()); - } - } - return $success; + return drupal_unlink($this->getFilePath($name)); } /** @@ -238,7 +229,12 @@ $success = FALSE; } } - + if ($success && $this->collection != StorageInterface::DEFAULT_COLLECTION) { + // Remove empty directories. + if (!(new \FilesystemIterator($this->getCollectionDirectory()))->valid()) { + drupal_rmdir($this->getCollectionDirectory()); + } + } return $success; } @@ -310,9 +306,12 @@ $collections[] = $collection . '.' . $sub_collection; } } - else { - // The directory has no subdirectories. Therefore add each directory - // to list of collections to be returned by the helper. + // Check that the collection is valid by searching if for configuration + // objects. A directory without any configuration objects is not a valid + // collection. + // \GlobIterator on Windows requires an absolute path. + $files = new \GlobIterator(realpath($directory . '/' . $collection) . '/*.' . $this->getFileExtension()); + if (count($files)) { $collections[] = $collection; } } diff -u b/core/lib/Drupal/Core/Config/StorageInterface.php b/core/lib/Drupal/Core/Config/StorageInterface.php --- b/core/lib/Drupal/Core/Config/StorageInterface.php +++ b/core/lib/Drupal/Core/Config/StorageInterface.php @@ -176,13 +176,7 @@ * regex [a-zA-Z_.]. A storage does not need to have a collection set. * However, if a collection is set, then storage should use it to store * configuration in a way that allows retrieval of configuration for a - * particular collection. Collections can be nested, for example - * 'language.de'. If this is a file system then we could create a language - * folder with a subfolder named de. If this is a database table then there - * could be a collection column which will store the value 'language.de'. - * Storage nested levels should be consistent. If a collection with the name - * 'language.de' exists then a collections with the names 'language' or - * 'language.en.gb' should not be used. + * particular collection. * * @return \Drupal\Core\Config\StorageInterface * A new instance of the storage backend with the collection set. diff -u b/core/modules/config/lib/Drupal/config/Tests/Storage/ConfigStorageTestBase.php b/core/modules/config/lib/Drupal/config/Tests/Storage/ConfigStorageTestBase.php --- b/core/modules/config/lib/Drupal/config/Tests/Storage/ConfigStorageTestBase.php +++ b/core/modules/config/lib/Drupal/config/Tests/Storage/ConfigStorageTestBase.php @@ -232,6 +232,21 @@ $alt_storage->delete($name); $this->assertIdentical(array('collection.sub.another', 'collection.sub.new'), $this->storage->getAllCollectionNames()); + // Create configuration in collection called 'collection'. This ensures that + // FileStorage's collection storage works regardless of its use of + // subdirectories. + $parent_storage = $this->storage->createCollection('collection'); + $this->assertFalse($parent_storage->exists($name)); + $this->assertEqual(array(), $parent_storage->listAll()); + $parent_storage->write($name, $new_data); + $this->assertIdentical($result, TRUE); + $this->assertIdentical($new_data, $parent_storage->read($name)); + $this->assertEqual(array($name), $parent_storage->listAll()); + $this->assertTrue($parent_storage->exists($name)); + $this->assertIdentical(array('collection', 'collection.sub.another', 'collection.sub.new'), $this->storage->getAllCollectionNames()); + $parent_storage->deleteAll(); + $this->assertIdentical(array('collection.sub.another', 'collection.sub.new'), $this->storage->getAllCollectionNames()); + // Check that the having an empty collection-less storage does not break // anything. Before deleting check that the previous delete did not affect // data in another collection.