diff --git a/core/core.services.yml b/core/core.services.yml index 18e37f9..7170275 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -67,16 +67,12 @@ services: factory_method: get factory_service: cache_factory arguments: [data] - config.cachedstorage.storage: - class: Drupal\Core\Config\FileStorage - factory_class: Drupal\Core\Config\FileStorageFactory - factory_method: getActive config.manager: class: Drupal\Core\Config\ConfigManager arguments: ['@entity.manager', '@config.factory', '@config.typed', '@string_translation', '@config.storage'] config.storage: - class: Drupal\Core\Config\CachedStorage - arguments: ['@config.cachedstorage.storage', '@cache.config'] + class: Drupal\Core\Config\DatabaseStorage + arguments: ['@database', 'config'] config.factory: class: Drupal\Core\Config\ConfigFactory tags: diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc index a704ebf..9cc33ec 100644 --- a/core/includes/bootstrap.inc +++ b/core/includes/bootstrap.inc @@ -326,12 +326,12 @@ function find_conf_path($http_host, $script_name, $require_settings = TRUE) { * * @param string $type * (optional) The type of config directory to return. Drupal core provides - * 'active' and 'staging'. Defaults to CONFIG_ACTIVE_DIRECTORY. + * 'active' and 'staging'. Defaults to CONFIG_STAGING_DIRECTORY. * * @return string * The configuration directory path. */ -function config_get_config_directory($type = CONFIG_ACTIVE_DIRECTORY) { +function config_get_config_directory($type = CONFIG_STAGING_DIRECTORY) { global $config_directories; if (!empty($config_directories[$type])) { diff --git a/core/includes/file.inc b/core/includes/file.inc index baaf654..6bc889f 100644 --- a/core/includes/file.inc +++ b/core/includes/file.inc @@ -575,7 +575,6 @@ function file_ensure_htaccess() { file_save_htaccess('private://', TRUE); } file_save_htaccess('temporary://', TRUE); - file_save_htaccess(config_get_config_directory(), TRUE); file_save_htaccess(config_get_config_directory(CONFIG_STAGING_DIRECTORY), TRUE); } diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc index d335e65..733d0b4 100644 --- a/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -438,7 +438,7 @@ function install_begin_request(&$install_state) { // Ensure that the active configuration directory is empty before installation // starts. if ($install_state['config_verified'] && empty($task)) { - $config = glob(config_get_config_directory(CONFIG_ACTIVE_DIRECTORY) . '/*.' . FileStorage::getFileExtension()); + $config = Database::getConnection()->schema()->tableExists('config');; if (!empty($config)) { $task = NULL; throw new AlreadyInstalledException($container->get('string_translation')); diff --git a/core/includes/install.inc b/core/includes/install.inc index 6f61503..d694d10 100644 --- a/core/includes/install.inc +++ b/core/includes/install.inc @@ -177,10 +177,6 @@ function drupal_get_database_types() { * and comment properties. * @code * $settings['config_directories'] = array( - * CONFIG_ACTIVE_DIRECTORY => (object) array( - * 'value' => 'config_hash/active' - * 'required' => TRUE, - * ), * CONFIG_STAGING_DIRECTORY => (object) array( * 'value' => 'config_hash/staging', * 'required' => TRUE, @@ -462,10 +458,6 @@ function drupal_install_config_directories() { if (empty($config_directories)) { $config_directories_hash = Crypt::randomBytesBase64(55); $settings['config_directories'] = array( - CONFIG_ACTIVE_DIRECTORY => (object) array( - 'value' => conf_path() . '/files/config_' . $config_directories_hash . '/active', - 'required' => TRUE, - ), CONFIG_STAGING_DIRECTORY => (object) array( 'value' => conf_path() . '/files/config_' . $config_directories_hash . '/staging', 'required' => TRUE, @@ -476,7 +468,7 @@ function drupal_install_config_directories() { } // Ensure the config directories exist or can be created, and are writable. - foreach (array(CONFIG_ACTIVE_DIRECTORY, CONFIG_STAGING_DIRECTORY) as $config_type) { + foreach (array(CONFIG_STAGING_DIRECTORY) as $config_type) { // This should never fail, since if the config directory was specified in // settings.php it will have already been created and verified earlier, and // if it wasn't specified in settings.php, it is created here inside the @@ -495,9 +487,6 @@ function drupal_install_config_directories() { // created, we have to write out the README rather than just adding it // to the drupal core repo. switch ($config_type) { - case CONFIG_ACTIVE_DIRECTORY: - $text = 'This directory contains the active configuration for your Drupal site. To move this configuration between environments, contents from this directory should be placed in the staging directory on the target server. To make this configuration active, see admin/config/development/configuration/sync on the target server.'; - break; case CONFIG_STAGING_DIRECTORY: $text = 'This directory contains configuration to be imported into your Drupal site. To make this configuration active, see admin/config/development/configuration/sync.'; break; diff --git a/core/lib/Drupal/Core/Config/BootstrapConfigStorageFactory.php b/core/lib/Drupal/Core/Config/BootstrapConfigStorageFactory.php index e075261..1df8f07 100644 --- a/core/lib/Drupal/Core/Config/BootstrapConfigStorageFactory.php +++ b/core/lib/Drupal/Core/Config/BootstrapConfigStorageFactory.php @@ -8,6 +8,7 @@ namespace Drupal\Core\Config; use Drupal\Component\Utility\Settings; +use Drupal\Core\Database\Database; /** * Defines a factory for retrieving the config storage used pre-kernel. @@ -26,7 +27,7 @@ public static function get() { return call_user_func($drupal_bootstrap_config_storage); } else { - return new FileStorage(config_get_config_directory(CONFIG_ACTIVE_DIRECTORY)); + return new DatabaseStorage(Database::getConnection(), 'config'); } } diff --git a/core/lib/Drupal/Core/Config/DatabaseStorage.php b/core/lib/Drupal/Core/Config/DatabaseStorage.php index fd8f2ee..aa0e022 100644 --- a/core/lib/Drupal/Core/Config/DatabaseStorage.php +++ b/core/lib/Drupal/Core/Config/DatabaseStorage.php @@ -176,7 +176,7 @@ public function decode($raw) { */ public function listAll($prefix = '') { return $this->connection->query('SELECT name FROM {' . $this->connection->escapeTable($this->table) . '} WHERE name LIKE :name', array( - ':name' => db_like($prefix) . '%', + ':name' => $this->connection->escapeLike($prefix) . '%', ), $this->options)->fetchCol(); } diff --git a/core/lib/Drupal/Core/DependencyInjection/UpdateServiceProvider.php b/core/lib/Drupal/Core/DependencyInjection/UpdateServiceProvider.php index 4776214..44e66d1 100644 --- a/core/lib/Drupal/Core/DependencyInjection/UpdateServiceProvider.php +++ b/core/lib/Drupal/Core/DependencyInjection/UpdateServiceProvider.php @@ -31,8 +31,9 @@ public function register(ContainerBuilder $container) { // Prevent config from accessing {cache_config}. // @see $conf['cache_classes'], update_prepare_d8_bootstrap() $container - ->register('config.storage', 'Drupal\Core\Config\FileStorage') - ->addArgument(config_get_config_directory(CONFIG_ACTIVE_DIRECTORY)); + ->register('config.storage', 'Drupal\Core\Config\DataBaseStorage') + ->addArgument(new Reference('database')) + ->addArgument('config'); $container->register('module_handler', 'Drupal\Core\Extension\UpdateModuleHandler') ->addArgument('%container.modules%'); $container diff --git a/core/modules/config/lib/Drupal/config/Controller/ConfigController.php b/core/modules/config/lib/Drupal/config/Controller/ConfigController.php index 18f6287..c79b8cb 100644 --- a/core/modules/config/lib/Drupal/config/Controller/ConfigController.php +++ b/core/modules/config/lib/Drupal/config/Controller/ConfigController.php @@ -12,6 +12,7 @@ use Drupal\Core\Config\StorageInterface; use Drupal\Core\DependencyInjection\ContainerInjectionInterface; use Drupal\system\FileDownloadController; +use Symfony\Component\Yaml\Dumper; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\Request; @@ -81,13 +82,15 @@ public function __construct(StorageInterface $target_storage, StorageInterface $ * Downloads a tarball of the site configuration. */ public function downloadExport() { + file_unmanaged_delete(file_directory_temp() . '/config.tar.gz'); + + $dumper = new Dumper(); + $dumper->setIndentation(2); + $archiver = new ArchiveTar(file_directory_temp() . '/config.tar.gz', 'gz'); - $config_dir = config_get_config_directory(); - $config_files = array(); - foreach (\Drupal::service('config.storage')->listAll() as $config_name) { - $config_files[] = $config_dir . '/' . $config_name . '.yml'; + foreach (\Drupal::service('config.storage')->listAll() as $name) { + $archiver->addString("$name.yml", $dumper->dump(\Drupal::config($name)->get(), PHP_INT_MAX, 0, TRUE)); } - $archiver->createModify($config_files, '', config_get_config_directory()); $request = new Request(array('file' => 'config.tar.gz')); return $this->fileDownloadController->download($request, 'temporary'); diff --git a/core/modules/config/lib/Drupal/config/Form/ConfigSingleExportForm.php b/core/modules/config/lib/Drupal/config/Form/ConfigSingleExportForm.php index 101dacb..7d0c465 100644 --- a/core/modules/config/lib/Drupal/config/Form/ConfigSingleExportForm.php +++ b/core/modules/config/lib/Drupal/config/Form/ConfigSingleExportForm.php @@ -12,6 +12,7 @@ use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Form\FormBase; use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\Yaml\Dumper; /** * Provides a form for exporting a single configuration file. @@ -33,6 +34,13 @@ class ConfigSingleExportForm extends FormBase { protected $configStorage; /** + * The config storage. + * + * @var \Symfony\Component\Yaml\Dumper + */ + protected $dumper; + + /** * Tracks the valid config entity type definitions. * * @var \Drupal\Core\Entity\EntityTypeInterface[] @@ -46,10 +54,14 @@ class ConfigSingleExportForm extends FormBase { * The entity manager. * @param \Drupal\Core\Config\StorageInterface $config_storage * The config storage. + * @param \Symfony\Component\Yaml\Dumper $dumper + * The yaml dumper. */ - public function __construct(EntityManagerInterface $entity_manager, StorageInterface $config_storage) { + public function __construct(EntityManagerInterface $entity_manager, StorageInterface $config_storage, Dumper $dumper) { $this->entityManager = $entity_manager; $this->configStorage = $config_storage; + $this->dumper = $dumper; + $this->dumper->setIndentation(2); } /** @@ -58,7 +70,8 @@ public function __construct(EntityManagerInterface $entity_manager, StorageInter public static function create(ContainerInterface $container) { return new static( $container->get('entity.manager'), - $container->get('config.storage') + $container->get('config.storage'), + new Dumper() ); } @@ -151,8 +164,7 @@ public function updateExport($form, &$form_state) { $name = $form_state['values']['config_name']; } // Read the raw data for this config name, encode it, and display it. - $data = $this->configStorage->read($name); - $form['export']['#value'] = $this->configStorage->encode($data); + $form['export']['#value'] = $this->dumper->dump($this->configStorage->read($name), PHP_INT_MAX, 0, TRUE); $form['export']['#description'] = $this->t('The filename is %name.', array('%name' => $name . '.yml')); return $form['export']; } diff --git a/core/modules/config_translation/lib/Drupal/config_translation/Tests/ConfigTranslationUiTest.php b/core/modules/config_translation/lib/Drupal/config_translation/Tests/ConfigTranslationUiTest.php index 405aaf5..cb07cd4 100644 --- a/core/modules/config_translation/lib/Drupal/config_translation/Tests/ConfigTranslationUiTest.php +++ b/core/modules/config_translation/lib/Drupal/config_translation/Tests/ConfigTranslationUiTest.php @@ -368,7 +368,6 @@ public function testContactConfigEntityTranslation() { */ public function testDateFormatTranslation() { $this->drupalLogin($this->admin_user); - $file_storage = new FileStorage($this->configDirectories[CONFIG_ACTIVE_DIRECTORY]); $this->drupalGet('admin/config/regional/date-time'); diff --git a/core/modules/simpletest/lib/Drupal/simpletest/DrupalUnitTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/DrupalUnitTestBase.php index 7737cc8..65deaf6 100644 --- a/core/modules/simpletest/lib/Drupal/simpletest/DrupalUnitTestBase.php +++ b/core/modules/simpletest/lib/Drupal/simpletest/DrupalUnitTestBase.php @@ -103,10 +103,15 @@ protected function beforePrepareEnvironment() { * * @see config_get_config_directory() */ - protected function prepareConfigDirectories() { + protected function prepareConfigStorage() { $this->configDirectories = array(); include_once DRUPAL_ROOT . '/core/includes/install.inc'; - foreach (array(CONFIG_ACTIVE_DIRECTORY, CONFIG_STAGING_DIRECTORY) as $type) { + // Create the configuration table. + module_load_install('system'); + $schema = system_schema(); + Database::getConnection()->schema()->createTable('config', $schema['config']); + //$this->installSchema('system', 'config'); + foreach (array(CONFIG_STAGING_DIRECTORY) as $type) { // Assign the relative path to the global variable. $path = $this->siteDirectory . '/config_' . $type; $GLOBALS['config_directories'][$type] = $path; @@ -127,9 +132,6 @@ protected function setUp() { parent::setUp(); - // Create and set new configuration directories. - $this->prepareConfigDirectories(); - // Build a minimal, partially mocked environment for unit tests. $this->containerBuild(\Drupal::getContainer()); // Make sure it survives kernel rebuilds. @@ -137,7 +139,8 @@ protected function setUp() { \Drupal::state()->set('system.module.files', $this->moduleFiles); \Drupal::state()->set('system.theme.files', $this->themeFiles); - + // Create and set new configuration directories. + $this->prepareConfigStorage(); // Bootstrap the kernel. // No need to dump it; this test runs in-memory. $this->kernel = new DrupalKernel('unit_testing', drupal_classloader(), FALSE); @@ -225,8 +228,9 @@ public function containerBuild(ContainerBuilder $container) { $container->register('cache_factory', 'Drupal\Core\Cache\MemoryBackendFactory'); $container - ->register('config.storage', 'Drupal\Core\Config\FileStorage') - ->addArgument($this->configDirectories[CONFIG_ACTIVE_DIRECTORY]); + ->register('config.storage', 'Drupal\Core\Config\DatabaseStorage') + ->addArgument(Database::getConnection()) + ->addArgument('config'); $this->settingsSet('keyvalue_default', 'keyvalue.memory'); $container->set('keyvalue.memory', $this->keyValueFactory); diff --git a/core/modules/system/system.install b/core/modules/system/system.install index ca5d128..fc74354 100644 --- a/core/modules/system/system.install +++ b/core/modules/system/system.install @@ -361,7 +361,6 @@ function system_requirements($phase) { // defined, the installer will create a valid config directory later, but // during runtime we must always display an error. if (!empty($GLOBALS['config_directories'])) { - $directories[] = config_get_config_directory(CONFIG_ACTIVE_DIRECTORY); $directories[] = config_get_config_directory(CONFIG_STAGING_DIRECTORY); } elseif ($phase != 'install') { @@ -970,7 +969,25 @@ function system_schema() { 'source_langcode_pid' => array('source', 'langcode', 'pid'), ), ); - + $schema['config'] = array( + 'description' => 'The base table for configuration data.', + 'fields' => array( + 'name' => array( + 'description' => 'Primary Key: Unique config object name.', + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => '', + ), + 'data' => array( + 'description' => 'A serialized configuration object data.', + 'type' => 'blob', + 'not null' => FALSE, + 'size' => 'big', + ), + ), + 'primary key' => array('name'), + ); $schema['config_snapshot'] = array( 'description' => 'Stores a snapshot of the last imported configuration.', 'fields' => array(