Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Importing Drupal 8 config programmatically
<?php
// Import arbitrary config from a variable.
// Assumes $data has the data you want to import for this config.
$config = \Drupal::service('config.factory')->getEditable('filter.format.basic_html');
$config->setData($data)->save();
// Or, re-import the default config for a module or profile, etc.
\Drupal::service('config.installer')->installDefaultConfig('module', 'my_custom_module');
// Or, import YAML config from an arbitrary file.
$config_path = drupal_get_path('module', 'my_custom_module') . '/config/install';
$source = new FileStorage($config_path);
$config_storage = \Drupal::service('config.storage');
$config_storage->write('filter.format.basic_html', $source->read('filter.format.basic_html'));
@sumanchalki

This comment has been minimized.

Copy link

@sumanchalki sumanchalki commented Jun 7, 2018

Good one.

@dlriley

This comment has been minimized.

Copy link

@dlriley dlriley commented Oct 24, 2018

Huge thanks - saved a lot of time!

@JPustkuchen

This comment has been minimized.

Copy link

@JPustkuchen JPustkuchen commented Jun 11, 2019

Very helpful, thank you!

You may also like this to install optional config e.g. in an update hook:

  $config_path = drupal_get_path('module', 'MY_MODULE') . '/config/optional';
  $config_source      = new \Drupal\Core\Config\FileStorage($config_path);
  \Drupal::service('config.installer')->installOptionalConfig($config_source);
@golddragon007

This comment has been minimized.

Copy link

@golddragon007 golddragon007 commented Sep 25, 2019

If you want to import all the site configs (drush required):

  /* @var \Drush\Drupal\Commands\config\ConfigImportCommands $drush_import */
  $container = \Drupal::getContainer();
  $drush_import = $container->get('config.import.commands');
  $storage_comparer = new StorageComparer(
    $container->get('config.storage.sync'),
    $container->get('config.storage')
  );
  $storage_comparer->createChangelist();
  $drush_import->doImport($storage_comparer);
@ojacquet

This comment has been minimized.

Copy link

@ojacquet ojacquet commented May 14, 2020

The first example does not work if you want to import new field storage definitions. This is what I've come up with:

$storage_comparer = new StorageComparer(
  \Drupal::service('config.storage.sync'),
  \Drupal::service('config.storage'),
  \Drupal::service('config.manager')
);
$config_importer = new ConfigImporter(
  $storage_comparer,
  \Drupal::service('event_dispatcher'),
  \Drupal::service('config.manager'),
  \Drupal::lock(),
  \Drupal::service('config.typed'),
  \Drupal::moduleHandler(),
  \Drupal::service('module_installer'),
  \Drupal::service('theme_handler'),
  \Drupal::service('string_translation')
);
$collection = StorageInterface::DEFAULT_COLLECTION;
$method = new ReflectionMethod($config_importer, 'processConfiguration');
$method->setAccessible(TRUE);
$method->invoke($config_importer, $collection, 'create', 'field.storage.node.field_subject');
$method->invoke($config_importer, $collection, 'create', 'field.field.node.mail.field_subject');
$context = [];
$config_importer->doSyncStep('finish', $context);

So, if you want to create fields it might be easier to just use Field(Storage)Config::create

@mike-potter

This comment has been minimized.

Copy link

@mike-potter mike-potter commented Aug 19, 2020

When writing an update hook it is often necessary to force a specific config item to be imported from the config/sync folder. Based on the OP, here is the helper function I use within the mymodule.install file. This should work in both D8 and D9.

use Drupal\Core\Site\Settings;
use Drupal\Core\Config\FileStorage;

/**
 * Helper function to import single config file.
 *
 * @param string $config_name
 *   The name of the config item to import from the config sync folder.
 */
function mymodule_import_single_config($config_name) {
  $config_path = Settings::get('config_sync_directory');
  $source = new FileStorage($config_path);
  $config_storage = \Drupal::service('config.storage');
  $config_storage->write($config_name, $source->read($config_name));
}

/**
 * Imports filter config so we can remove a related module.
 */
function p2_core_update_8001() {
  mymodule_import_single_config('filter.format.basic_html');
}
@rang501

This comment has been minimized.

Copy link

@rang501 rang501 commented Oct 5, 2020

It is not a good idea to write module config into active config directly, for example, it will erase some needed attributes, e.g _core and uuid which may cause issues later. It will also remove all other modifications by other modules if they are not imported into config (sometimes it is not possible due to dependencies like installation profile modules). Extra caution should be taken when updating config entities like fields, especially when creating them that way - db tables may not be created, entity API should be used instead.

My general advice when using this - update the parts you need not the whole configuration and when possible, use config entity object to change stuff.

@mike-potter

This comment has been minimized.

Copy link

@mike-potter mike-potter commented Oct 5, 2020

That's the point of the snippet above: it is reading the actual config file from the config/sync folder, which contains the _core and uuid values already. Updating parts of a configuration is usually more fraught with danger. Importing config like this during an update hook is only a last resort however.

@rang501

This comment has been minimized.

Copy link

@rang501 rang501 commented Oct 5, 2020

Sorry, I didn't specify, I meant the original snippet it just imports from module config, which doesn't (shouldn't) contain these values.
I just wanted to say something to other developers who will find this through Google search, that the original code might break stuff.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.