/** * {@inheritdoc} */ public function loadOverrides($names) { $overrides = array(); // loadOverrides() runs on config entities, which means that if we try // to run this routine on our own data, then we end up in an infinite loop. // So ensure that we are _not_ looking up a domain.record.*. $check = current($names); $list = explode('.', $check); if (isset($list[0]) && isset($list[1]) && $list[0] == 'domain' && $list[1] == 'record') { return $overrides; } $this->initiateContext(); if (!empty($this->domain)) { foreach ($names as $name) { $config_name = $this->getDomainConfigName($name, $this->domain); // Check to see if the config storage has an appropriately named file // containing override data. if ($override = $this->storage->read($config_name['langcode'])) { $overrides[$name] = $override; } elseif ($override = $this->storage->read($config_name['domain'])) { $overrides[$name] = $override; } } } return $overrides; }
protected function getConfigNames($config_type) { $this->configStorage = $this->getDrupalService('config.storage'); // For a given entity type, load all entities. if ($config_type && $config_type !== 'system.simple') { $entity_storage = $this->entityManager->getStorage($config_type); foreach ($entity_storage->loadMultiple() as $entity) { $entity_id = $entity->id(); $label = $entity->label() ?: $entity_id; $names[$entity_id] = $label; } } else { // Gather the config entity prefixes. $config_prefixes = array_map(function ($definition) { return $definition->getConfigPrefix() . '.'; }, $this->definitions); // Find all config, and then filter our anything matching a config prefix. $names = $this->configStorage->listAll(); $names = array_combine($names, $names); foreach ($names as $config_name) { foreach ($config_prefixes as $config_prefix) { if (strpos($config_name, $config_prefix) === 0) { unset($names[$config_name]); } } } } return $names; }
/** * Returns a map of all config object names and their folders. * * The list is based on enabled modules and themes. The active configuration * storage is used rather than \Drupal\Core\Extension\ModuleHandler and * \Drupal\Core\Extension\ThemeHandler in order to resolve circular * dependencies between these services and \Drupal\Core\Config\ConfigInstaller * and \Drupal\Core\Config\TypedConfigManager. * * @return array * An array mapping config object names with directories. */ protected function getAllFolders() { if (!isset($this->folders)) { $this->folders = array(); $this->folders += $this->getComponentNames('core', array('core')); $extensions = $this->configStorage->read('core.extension'); if (!empty($extensions['module'])) { $modules = $extensions['module']; if (!$this->includeProfile) { if ($install_profile = Settings::get('install_profile')) { unset($modules[$install_profile]); } } $this->folders += $this->getComponentNames('module', array_keys($modules)); } if (!empty($extensions['theme'])) { $this->folders += $this->getComponentNames('theme', array_keys($extensions['theme'])); } // The install profile can override module default configuration. We do // this by replacing the config file path from the module/theme with the // install profile version if there are any duplicates. $profile_folders = $this->getComponentNames('profile', array(drupal_get_profile())); $folders_to_replace = array_intersect_key($profile_folders, $this->folders); if (!empty($folders_to_replace)) { $this->folders = array_merge($this->folders, $folders_to_replace); } } return $this->folders; }
/** * Copies configuration objects from source storage to target storage. * * @param \Drupal\Core\Config\StorageInterface $source_storage * The source config storage service. * @param \Drupal\Core\Config\StorageInterface $target_storage * The target config storage service. */ protected function copyConfig(StorageInterface $source_storage, StorageInterface $target_storage) { $target_storage->deleteAll(); foreach ($source_storage->listAll() as $name) { $target_storage->write($name, $source_storage->read($name)); } }
public function filterWrite($name, array $data, StorageInterface $storage) { if ($name != 'core.extension') { return $data; } $originalData = $storage->read($name); return $this->filterOutIgnored($data, $storage->read($name)); }
/** * @covers ::rename */ public function testRename() { $old = new Config($this->randomMachineName(), $this->storage, $this->eventDispatcher, $this->typedConfig); $new = new Config($this->randomMachineName(), $this->storage, $this->eventDispatcher, $this->typedConfig); $this->storage->expects($this->exactly(2))->method('readMultiple')->willReturnMap([[[$old->getName()], $old->getRawData()], [[$new->getName()], $new->getRawData()]]); $this->cacheTagsInvalidator->expects($this->once())->method('invalidateTags')->with($old->getCacheTags()); $this->storage->expects($this->once())->method('rename')->with($old->getName(), $new->getName()); $this->configFactory->rename($old->getName(), $new->getName()); }
/** * Returns a map of all config object names and their folders. * * The list is based on enabled modules and themes. The active configuration * storage is used rather than \Drupal\Core\Extension\ModuleHandler and * \Drupal\Core\Extension\ThemeHandler in order to resolve circular * dependencies between these services and \Drupal\Core\Config\ConfigInstaller * and \Drupal\Core\Config\TypedConfigManager. * * @return array * An array mapping config object names with directories. */ protected function getAllFolders() { if (!isset($this->folders)) { $this->folders = array(); $this->folders += $this->getCoreNames(); $install_profile = Settings::get('install_profile'); $profile = drupal_get_profile(); $extensions = $this->configStorage->read('core.extension'); // @todo Remove this scan as part of https://www.drupal.org/node/2186491 $listing = new ExtensionDiscovery(\Drupal::root()); if (!empty($extensions['module'])) { $modules = $extensions['module']; // Remove the install profile as this is handled later. unset($modules[$install_profile]); $profile_list = $listing->scan('profile'); if ($profile && isset($profile_list[$profile])) { // Prime the drupal_get_filename() static cache with the profile info // file location so we can use drupal_get_path() on the active profile // during the module scan. // @todo Remove as part of https://www.drupal.org/node/2186491 drupal_get_filename('profile', $profile, $profile_list[$profile]->getPathname()); } $module_list_scan = $listing->scan('module'); $module_list = array(); foreach (array_keys($modules) as $module) { if (isset($module_list_scan[$module])) { $module_list[$module] = $module_list_scan[$module]; } } $this->folders += $this->getComponentNames($module_list); } if (!empty($extensions['theme'])) { $theme_list_scan = $listing->scan('theme'); foreach (array_keys($extensions['theme']) as $theme) { if (isset($theme_list_scan[$theme])) { $theme_list[$theme] = $theme_list_scan[$theme]; } } $this->folders += $this->getComponentNames($theme_list); } if ($this->includeProfile) { // The install profile can override module default configuration. We do // this by replacing the config file path from the module/theme with the // install profile version if there are any duplicates. if (isset($profile)) { if (!isset($profile_list)) { $profile_list = $listing->scan('profile'); } if (isset($profile_list[$profile])) { $profile_folders = $this->getComponentNames(array($profile_list[$profile])); $this->folders = $profile_folders + $this->folders; } } } } return $this->folders; }
/** * {@inheritdoc} */ public function getDefinitions() { $definitions = array(); foreach ($this->schemaStorage->readMultiple($this->schemaStorage->listAll()) as $schema) { foreach ($schema as $type => $definition) { $definitions[$type] = $definition; } } return $definitions; }
public function filterWrite($name, array $data, StorageInterface $storage) { if ($name == 'core.extension') { return $this->filterOutIgnored($data, $storage->read($name)); } $dependent_configs = $this->getAllDependentConfigs($storage); if (in_array($name, $dependent_configs)) { $data = ($existing = $storage->read($name)) ? $existing : NULL; } return $data; }
/** * Gets the configuration storage that provides the active configuration. * * @param string $collection * (optional) The configuration collection. Defaults to the default * collection. * * @return \Drupal\Core\Config\StorageInterface * The configuration storage that provides the default configuration. */ protected function getActiveStorage($collection = StorageInterface::DEFAULT_COLLECTION) { if ($this->activeStorage->getCollectionName() != $collection) { $this->activeStorage = $this->activeStorage->createCollection($collection); } return $this->activeStorage; }
/** * Handles switching the configuration type selector. */ protected function findConfiguration($config_type) { $names = array('' => $this->t('- Select -')); // For a given entity type, load all entities. if ($config_type && $config_type !== 'system.simple') { $entity_storage = $this->entityManager->getStorage($config_type); foreach ($entity_storage->loadMultiple() as $entity) { $entity_id = $entity->id(); if ($label = $entity->label()) { $names[$entity_id] = new TranslatableMarkup('@label (@id)', ['@label' => $label, '@id' => $entity_id]); } else { $names[$entity_id] = $entity_id; } } } else { // Gather the config entity prefixes. $config_prefixes = array_map(function (EntityTypeInterface $definition) { return $definition->getConfigPrefix() . '.'; }, $this->definitions); // Find all config, and then filter our anything matching a config prefix. $names = $this->configStorage->listAll(); $names = array_combine($names, $names); foreach ($names as $config_name) { foreach ($config_prefixes as $config_prefix) { if (strpos($config_name, $config_prefix) === 0) { unset($names[$config_name]); } } } } return $names; }
/** * {@inheritdoc} */ public function getStorage($langcode) { if (!isset($this->storages[$langcode])) { $this->storages[$langcode] = $this->baseStorage->createCollection($this->createConfigCollectionName($langcode)); } return $this->storages[$langcode]; }
/** * Returns a cache ID prefix to use for the collection. * * @return string * The cache ID prefix. */ protected function getCollectionPrefix() { $collection = $this->storage->getCollectionName(); if ($collection == StorageInterface::DEFAULT_COLLECTION) { return ''; } return $collection . ':'; }
/** * {@inheritdoc} */ public function getAllCollectionNames($include_default = TRUE) { $collections = array_unique(array_merge($this->sourceStorage->getAllCollectionNames(), $this->targetStorage->getAllCollectionNames())); if ($include_default) { array_unshift($collections, StorageInterface::DEFAULT_COLLECTION); } return $collections; }
/** * {@inheritdoc} */ public function getFromExtension($type, $name) { $full_name = $this->getFullName($type, $name); $value = $this->extensionConfigStorage->read($full_name); if (!$value) { $value = $this->extensionOptionalConfigStorage->read($full_name); } return $value; }
/** * {@inheritdoc} */ public function submitForm(array &$form, FormStateInterface $form_state) { if ($path = $form_state->getValue('import_tarball')) { $this->configStorage->deleteAll(); try { $archiver = new ArchiveTar($path, 'gz'); $files = array(); foreach ($archiver->listContent() as $file) { $files[] = $file['filename']; } $archiver->extractList($files, config_get_config_directory(CONFIG_STAGING_DIRECTORY)); drupal_set_message($this->t('Your configuration files were successfully uploaded, ready for import.')); $form_state->setRedirect('config.sync'); } catch (\Exception $e) { drupal_set_message($this->t('Could not extract the contents of the tar file. The error message is <em>@message</em>', array('@message' => $e->getMessage())), 'error'); } drupal_unlink($path); } }
/** * @covers ::importCurrencyLocale */ public function testImportCurrencyLocaleWithExistingCurrency() { $locale = $this->randomMachineName(); $currency_locale = $this->getMock(CurrencyLocaleInterface::class); $this->currencyLocaleStorage->expects($this->never())->method('create'); $this->currencyLocaleStorage->expects($this->once())->method('load')->with($locale)->willReturn($currency_locale); $this->configStorage->expects($this->never())->method('read'); $this->sut->setConfigStorage($this->configStorage); $this->assertFalse($this->sut->importCurrencyLocale($locale)); }
/** * Test the import subscriber. */ public function testSubscribers() { // Without this the config exporter breaks. \Drupal::service('config.installer')->installDefaultConfig('module', 'config_devel'); $filename = vfsStream::url('public://' . static::CONFIGNAME . '.yml'); drupal_mkdir(vfsStream::url('public://exported')); $exported_filename = vfsStream::url('public://exported/' . static::CONFIGNAME . '.yml'); \Drupal::configFactory()->getEditable('config_devel.settings')->set('auto_import', array(array('filename' => $filename, 'hash' => '')))->set('auto_export', array($exported_filename))->save(); $this->storage = \Drupal::service('config.storage'); $this->assertFalse($this->storage->exists(static::CONFIGNAME)); $subscriber = \Drupal::service('config_devel.auto_import_subscriber'); for ($i = 2; $i; $i--) { $data['label'] = $this->randomString(); file_put_contents($filename, Yaml::encode($data)); // The import fires an export too. $subscriber->autoImportConfig(); $this->doAssert($data, Yaml::decode(file_get_contents($exported_filename))); } }
protected function addConfigList($full_name, &$list) { if (!in_array($full_name, $list)) { array_unshift($list, $full_name); $value = $this->extensionStorage->read($full_name); if (isset($value['dependencies']['config'])) { foreach ($value['dependencies']['config'] as $config_name) { $this->addConfigList($config_name, $list); } } } }
/** * Compute the list of configuration names that match predefined languages. * * @return array * The list of configuration names that match predefined languages. */ protected function predefinedConfiguredLanguages() { $names = $this->configStorage->listAll('language.entity.'); $predefined_languages = $this->languageManager->getStandardLanguageList(); foreach ($names as $id => $name) { $langcode = str_replace('language.entity.', '', $name); if (!isset($predefined_languages[$langcode])) { unset($names[$id]); } } return array_values($names); }
/** * Updates all configuration translations for the names / languages provided. * * To be used when interface translation changes result in the need to update * configuration translations to keep them in sync. * * @param array $names * Array of names of configuration objects to update. * @param array $langcodes * (optional) Array of language codes to update. Defaults to all * configurable languages. * * @return int * Total number of configuration override and active configuration objects * updated (saved or removed). */ public function updateConfigTranslations(array $names, array $langcodes = array()) { $langcodes = $langcodes ? $langcodes : array_keys($this->languageManager->getLanguages()); $count = 0; foreach ($names as $name) { $translatable = $this->getTranslatableDefaultConfig($name); if (empty($translatable)) { // If there is nothing translatable in this configuration or not // supported, skip it. continue; } $active_langcode = $this->getActiveConfigLangcode($name); $active = $this->configStorage->read($name); foreach ($langcodes as $langcode) { $processed = $this->processTranslatableData($name, $active, $translatable, $langcode); if ($langcode != $active_langcode) { // If the language code is not the same as the active storage // language, we should update a configuration override. if (!empty($processed)) { // Update translation data in configuration override. $this->saveTranslationOverride($name, $langcode, $processed); $count++; } else { $override = $this->languageManager->getLanguageConfigOverride($langcode, $name); if (!$override->isNew()) { $data = $this->filterOverride($override->get(), $translatable); if (empty($data)) { // Delete language override if there is no data left at all. // This means all prior translations in the override were locale // managed. $this->deleteTranslationOverride($name, $langcode); $count++; } else { // If there were translatable elements besides locale managed // items, save with only those, and remove the ones managed // by locale only. $this->saveTranslationOverride($name, $langcode, $data); $count++; } } } } elseif (locale_is_translatable($langcode)) { // If the language code is the active storage language, we should // update. If it is English, we should only update if English is also // translatable. $active = NestedArray::mergeDeepArray(array($active, $processed), TRUE); $this->saveTranslationActive($name, $active); $count++; } } } return $count; }
/** * Gets configuration names associated with components. * * @param array $components * (optional) Array of component lists indexed by type. If not present or it * is an empty array, it will update all components. * * @return array * Array of configuration object names. */ public function getComponentNames(array $components) { $components = array_filter($components); if ($components) { $names = array(); foreach ($components as $type => $list) { // InstallStorage::getComponentNames returns a list of folders keyed by // config name. $names = array_merge($names, array_keys($this->installStorage->getComponentNames($type, $list))); } return $names; } else { return $this->installStorage->listAll(); } }
/** * {@inheritdoc} */ public function getConfigDependencyManager() { $dependency_manager = new ConfigDependencyManager(); // This uses the configuration storage directly to avoid blowing the static // caches in the configuration factory and the configuration entity system. // Additionally this ensures that configuration entity dependency discovery // has no dependencies on the config entity classes. Assume data with UUID // is a config entity. Only configuration entities can be depended on so we // can ignore everything else. $data = array_filter($this->activeStorage->readMultiple($this->activeStorage->listAll()), function ($config) { return isset($config['uuid']); }); $dependency_manager->setData($data); return $dependency_manager; }
/** * Updates all configuration translations for the names / languages provided. * * To be used when interface translation changes result in the need to update * configuration translations to keep them in sync. * * @param array $names * Array of names of configuration objects to update. * @param array $langcodes * (optional) Array of language codes to update. Defaults to all * configurable languages. * * @return int * Total number of configuration override and active configuration objects * updated (saved or removed). */ public function updateConfigTranslations(array $names, array $langcodes = array()) { $langcodes = $langcodes ? $langcodes : array_keys($this->languageManager->getLanguages()); $count = 0; foreach ($names as $name) { $translatable = $this->getTranslatableDefaultConfig($name); if (empty($translatable)) { // If there is nothing translatable in this configuration or not // supported, skip it. continue; } $active_langcode = $this->getActiveConfigLangcode($name); $active = $this->configStorage->read($name); foreach ($langcodes as $langcode) { $processed = $this->processTranslatableData($name, $active, $translatable, $langcode); // If the language code is not the same as the active storage // language, we should update the configuration override. if ($langcode != $active_langcode) { $override = $this->languageManager->getLanguageConfigOverride($langcode, $name); // Filter out locale managed configuration keys so that translations // removed from Locale will be reflected in the config override. $data = $this->filterOverride($override->get(), $translatable); if (!empty($processed)) { // Merge in the Locale managed translations with existing data. $data = NestedArray::mergeDeepArray(array($data, $processed), TRUE); } if (empty($data) && !$override->isNew()) { // The configuration override contains Locale overrides that no // longer exist. $this->deleteTranslationOverride($name, $langcode); $count++; } elseif (!empty($data)) { // Update translation data in configuration override. $this->saveTranslationOverride($name, $langcode, $data); $count++; } } elseif (locale_is_translatable($langcode)) { // If the language code is the active storage language, we should // update. If it is English, we should only update if English is also // translatable. $active = NestedArray::mergeDeepArray(array($active, $processed), TRUE); $this->saveTranslationActive($name, $active); $count++; } } } return $count; }
/** * {@inheritdoc} */ public function detectOverrides(array $feature, $include_new = FALSE) { $config_diff = \Drupal::service('config_update.config_diff'); $different = array(); foreach ($feature['config'] as $name) { $active = $this->configStorage->read($name); $extension = $this->extensionStorages->read($name); $extension = !empty($extension) ? $extension : array(); if (($include_new || !empty($extension)) && !$config_diff->same($extension, $active)) { $different[] = $name; } } if (!empty($different)) { $feature['state'] = FeaturesManagerInterface::STATE_OVERRIDDEN; } return $different; }
/** * @covers ::createChangelist */ public function testCreateChangelistUpdate() { $target_data = $source_data = $this->getConfigData(); $source_data['system.site']['title'] = 'Drupal New!'; $source_data['field.field.node.article.body']['new_config_key'] = 'new data'; $source_data['field.storage.node.body']['new_config_key'] = 'new data'; $this->sourceStorage->expects($this->once())->method('listAll')->will($this->returnValue(array_keys($source_data))); $this->targetStorage->expects($this->once())->method('listAll')->will($this->returnValue(array_keys($target_data))); $this->sourceStorage->expects($this->once())->method('readMultiple')->will($this->returnValue($source_data)); $this->targetStorage->expects($this->once())->method('readMultiple')->will($this->returnValue($target_data)); $this->sourceStorage->expects($this->once())->method('getAllCollectionNames')->will($this->returnValue(array())); $this->targetStorage->expects($this->once())->method('getAllCollectionNames')->will($this->returnValue(array())); $this->storageComparer->createChangelist(); $expected = array('field.storage.node.body', 'system.site', 'field.field.node.article.body'); $this->assertEquals($expected, $this->storageComparer->getChangelist('update')); $this->assertEmpty($this->storageComparer->getChangelist('create')); $this->assertEmpty($this->storageComparer->getChangelist('delete')); }
/** * {@inheritdoc} */ public function findMissingContentDependencies() { $content_dependencies = array(); $missing_dependencies = array(); foreach ($this->activeStorage->readMultiple($this->activeStorage->listAll()) as $config_data) { if (isset($config_data['dependencies']['content'])) { $content_dependencies = array_merge($content_dependencies, $config_data['dependencies']['content']); } } foreach (array_unique($content_dependencies) as $content_dependency) { // Format of the dependency is entity_type:bundle:uuid. list($entity_type, $bundle, $uuid) = explode(':', $content_dependency, 3); if (!$this->entityManager->loadEntityByUuid($entity_type, $uuid)) { $missing_dependencies[$uuid] = array('entity_type' => $entity_type, 'bundle' => $bundle, 'uuid' => $uuid); } } return $missing_dependencies; }
/** * {@inheritdoc} */ public function detectOverrides(Package $feature, $include_new = FALSE) { /** @var \Drupal\config_update\ConfigDiffInterface $config_diff */ $config_diff = \Drupal::service('config_update.config_diff'); $different = array(); foreach ($feature->getConfig() as $name) { $active = $this->configStorage->read($name); $extension = $this->extensionStorages->read($name); $extension = !empty($extension) ? $extension : array(); if (($include_new || !empty($extension)) && !$config_diff->same($extension, $active)) { $different[] = $name; } } if (!empty($different)) { $feature->setState(FeaturesManagerInterface::STATE_OVERRIDDEN); } return $different; }
/** * Downloads a tarball of the site configuration. */ public function downloadExport() { file_unmanaged_delete(file_directory_temp() . '/config.tar.gz'); $archiver = new ArchiveTar(file_directory_temp() . '/config.tar.gz', 'gz'); // Get raw configuration data without overrides. foreach ($this->configManager->getConfigFactory()->listAll() as $name) { $archiver->addString("{$name}.yml", Yaml::encode($this->configManager->getConfigFactory()->get($name)->getRawData())); } // Get all override data from the remaining collections. foreach ($this->targetStorage->getAllCollectionNames() as $collection) { $collection_storage = $this->targetStorage->createCollection($collection); foreach ($collection_storage->listAll() as $name) { $archiver->addString(str_replace('.', '/', $collection) . "/{$name}.yml", Yaml::encode($collection_storage->read($name))); } } $request = new Request(array('file' => 'config.tar.gz')); return $this->fileDownloadController->download($request, 'temporary'); }
/** * {@inheritdoc} */ protected function doLoadMultiple(array $ids = NULL) { $prefix = $this->getPrefix(); // Get the names of the configuration entities we are going to load. if ($ids === NULL) { $names = $this->configStorage->listAll($prefix); } else { $names = array(); foreach ($ids as $id) { // Add the prefix to the ID to serve as the configuration object name. $names[] = $prefix . $id; } } // Load all of the configuration entities. $records = array(); foreach ($this->configFactory->loadMultiple($names) as $config) { $records[$config->get($this->idKey)] = $config->get(); } return $this->mapFromStorageRecords($records); }