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; }
/** * {@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; }
/** * {@inheritdoc} */ public function listConfigByType($config_type) { // For a given entity type, load all entities. if ($config_type && $config_type !== FeaturesManagerInterface::SYSTEM_SIMPLE_CONFIG) { $entity_storage = $this->entityManager->getStorage($config_type); $names = []; foreach ($entity_storage->loadMultiple() as $entity) { $entity_id = $entity->id(); $label = $entity->label() ?: $entity_id; $names[$entity_id] = $label; } } else { $definitions = []; foreach ($this->entityManager->getDefinitions() as $entity_type => $definition) { if ($definition->isSubclassOf('Drupal\\Core\\Config\\Entity\\ConfigEntityInterface')) { $definitions[$entity_type] = $definition; } } // Gather the config entity prefixes. $config_prefixes = array_map(function (EntityTypeInterface $definition) { return $definition->getConfigPrefix() . '.'; }, $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 $item_name) { foreach ($config_prefixes as $config_prefix) { if (strpos($item_name, $config_prefix) === 0) { unset($names[$item_name]); } } } } return $names; }
/** * Tests an invalid storage. */ public function testInvalidStorage() { $name = 'config_test.storage'; // Write something to the valid storage to prove that the storages do not // pollute one another. $data = array('foo' => 'bar'); $result = $this->storage->write($name, $data); $this->assertIdentical($result, TRUE); $raw_data = $this->read($name); $this->assertIdentical($raw_data, $data); // Reading from a non-existing storage bin returns FALSE. $result = $this->invalidStorage->read($name); $this->assertIdentical($result, FALSE); // Deleting from a non-existing storage bin throws an exception. try { $this->invalidStorage->delete($name); $this->fail('Exception not thrown upon deleting from a non-existing storage bin.'); } catch (\Exception $e) { $class = get_class($e); $this->pass($class . ' thrown upon deleting from a non-existing storage bin.'); } // Listing on a non-existing storage bin returns an empty array. $result = $this->invalidStorage->listAll(); $this->assertIdentical($result, array()); // 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')); }
/** * 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; }
/** * 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)); } }
/** * {@inheritdoc} */ public function deleteAll($prefix = '') { $list = $this->storage->listAll(); $result = TRUE; foreach ($list as $name) { $result = $this->delete($name) ? $result : FALSE; } return $result; }
/** * Implements Drupal\Core\Config\StorageInterface::deleteAll(). */ public function deleteAll($prefix = '') { // If the cache was the first to be deleted, another process might start // rebuilding the cache before the storage is renamed. $names = $this->storage->listAll($prefix); if ($this->storage->deleteAll($prefix)) { $this->cache->deleteMultiple($this->getCacheKeys($names)); return TRUE; } return FALSE; }
/** * 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); }
/** * 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; }
/** * {@inheritdoc} */ public function getDefinitions() { if (!isset($this->definitions)) { if ($cache = $this->cache->get($this::CACHE_ID)) { $this->definitions = $cache->data; } else { $this->definitions = array(); foreach ($this->schemaStorage->readMultiple($this->schemaStorage->listAll()) as $schema) { foreach ($schema as $type => $definition) { $this->definitions[$type] = $definition; } } $this->cache->set($this::CACHE_ID, $this->definitions); } } return $this->definitions; }
/** * {@inheritdoc} */ public function listAll($prefix = '') { $names = $this->storage->listAll($prefix); $additional_names = []; if ($prefix === '') { $additional_names = array_keys($this->replacementData[$this->collection]); } else { foreach (array_keys($this->replacementData[$this->collection]) as $name) { if (strpos($name, $prefix) === 0) { $additional_names[] = $name; } } } if (!empty($additional_names)) { $names = array_unique(array_merge($names, $additional_names)); } return $names; }
/** * {@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; }
/** * Creates a high performant version of the ConfigDependencyManager. * * @return \Drupal\features\FeaturesConfigDependencyManager * A high performant version of the ConfigDependencyManager. * * @see \Drupal\Core\Config\Entity\ConfigDependencyManager */ protected function getFeaturesConfigDependencyManager() { $dependency_manager = new FeaturesConfigDependencyManager(); // Read all configuration using the factory. This ensures that multiple // deletes during the same request benefit from the static cache. Using the // factory also ensures 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_map(function (Drupal\Core\Config\ImmutableConfig $config) { $data = $config->get(); if (isset($data['uuid'])) { return $data; } return FALSE; }, $this->configFactory->loadMultiple($this->configStorage->listAll())); $dependency_manager->setData(array_filter($data)); return $dependency_manager; }
/** * {@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); }
/** * Loads the config records to examine for the query. * * @return array * Config records keyed by entity IDs. */ protected function loadRecords() { $prefix = $this->entityType->getConfigPrefix() . '.'; $prefix_length = strlen($prefix); // Search the conditions for restrictions on entity IDs. $ids = array(); if ($this->condition->getConjunction() == 'AND') { foreach ($this->condition->conditions() as $condition) { if (is_string($condition['field']) && $condition['field'] == $this->entityType->getKey('id')) { $operator = $condition['operator'] ?: (is_array($condition['value']) ? 'IN' : '='); if ($operator == '=') { $ids = array($condition['value']); } elseif ($operator == 'IN') { $ids = $condition['value']; } // We stop at the first restricting condition on ID. In the (weird) // case where there are additional restricting conditions, results // will be eliminated when the conditions are checked on the loaded // records. if ($ids) { break; } } } } // If there are conditions restricting config ID, we can narrow the list of // records to load and parse. if ($ids) { $names = array_map(function ($id) use($prefix) { return $prefix . $id; }, $ids); } else { $names = $this->configStorage->listAll($prefix); } // Load the corresponding records. $records = array(); foreach ($this->configFactory->loadMultiple($names) as $config) { $records[substr($config->getName(), $prefix_length)] = $config->get(); } return $records; }
/** * {@inheritdoc} */ function listConfig($list_type, $name) { $active_list = array(); $install_list = array(); $optional_list = array(); $definitions = $this->listTypes(); switch ($list_type) { case 'type': if ($name == 'system.all') { $active_list = $this->activeConfigStorage->listAll(); $install_list = $this->extensionConfigStorage->listAll(); $optional_list = $this->extensionOptionalConfigStorage->listAll(); } elseif ($name == 'system.simple') { // Listing is done by prefixes, and simple config doesn't have one. // So list all and filter out all known prefixes. $active_list = $this->omitKnownPrefixes($this->activeConfigStorage->listAll()); $install_list = $this->omitKnownPrefixes($this->extensionConfigStorage->listAll()); $optional_list = $this->omitKnownPrefixes($this->extensionOptionalConfigStorage->listAll()); } elseif (isset($this->definitions[$name])) { $definition = $this->definitions[$name]; $prefix = $definition->getConfigPrefix(); $active_list = $this->activeConfigStorage->listAll($prefix); $install_list = $this->extensionConfigStorage->listAll($prefix); $optional_list = $this->extensionOptionalConfigStorage->listAll($prefix); } break; case 'profile': $name = Settings::get('install_profile'); // Intentional fall-through here to the 'module' or 'theme' case. // Intentional fall-through here to the 'module' or 'theme' case. case 'module': case 'theme': $active_list = $this->activeConfigStorage->listAll(); $install_list = $this->listProvidedItems($list_type, $name); $optional_list = $this->listProvidedItems($list_type, $name, TRUE); break; } return array($active_list, $install_list, $optional_list); }
/** * {@inheritdoc} */ public function listAll($prefix = '') { return $this->baseStorage->listAll($prefix); }
/** * {@inheritdoc} */ public function buildForm(array $form, FormStateInterface $form_state) { $snapshot_comparer = new StorageComparer($this->activeStorage, $this->snapshotStorage, $this->configManager); if (!$form_state->getUserInput() && $snapshot_comparer->createChangelist()->hasChanges()) { $change_list = array(); foreach ($snapshot_comparer->getAllCollectionNames() as $collection) { foreach ($snapshot_comparer->getChangelist(NULL, $collection) as $config_names) { if (empty($config_names)) { continue; } foreach ($config_names as $config_name) { $change_list[] = $config_name; } } } sort($change_list); $change_list_render = array('#theme' => 'item_list', '#items' => $change_list); $change_list_html = drupal_render($change_list_render); drupal_set_message($this->t('Your current configuration has changed. Changes to these configuration items will be lost on the next synchronization: !changes', array('!changes' => $change_list_html)), 'warning'); } $form['actions'] = array('#type' => 'actions'); $form['actions']['submit'] = array('#type' => 'submit', '#value' => $this->t('Import all')); $source_list = $this->stagingStorage->listAll(); $storage_comparer = new StorageComparer($this->stagingStorage, $this->activeStorage, $this->configManager); if (empty($source_list) || !$storage_comparer->createChangelist()->hasChanges()) { $form['no_changes'] = array('#type' => 'table', '#header' => array('Name', 'Operations'), '#rows' => array(), '#empty' => $this->t('There are no configuration changes to import.')); $form['actions']['#access'] = FALSE; return $form; } elseif (!$storage_comparer->validateSiteUuid()) { drupal_set_message($this->t('The staged configuration cannot be imported, because it originates from a different site than this site. You can only synchronize configuration between cloned instances of this site.'), 'error'); $form['actions']['#access'] = FALSE; return $form; } else { // Store the comparer for use in the submit. $form_state->set('storage_comparer', $storage_comparer); } // Add the AJAX library to the form for dialog support. $form['#attached']['library'][] = 'core/drupal.ajax'; foreach ($storage_comparer->getAllCollectionNames() as $collection) { if ($collection != StorageInterface::DEFAULT_COLLECTION) { $form[$collection]['collection_heading'] = array('#type' => 'html_tag', '#tag' => 'h2', '#value' => $this->t('!collection configuration collection', array('!collection' => $collection))); } foreach ($storage_comparer->getChangelist(NULL, $collection) as $config_change_type => $config_names) { if (empty($config_names)) { continue; } // @todo A table caption would be more appropriate, but does not have the // visual importance of a heading. $form[$collection][$config_change_type]['heading'] = array('#type' => 'html_tag', '#tag' => 'h3'); switch ($config_change_type) { case 'create': $form[$collection][$config_change_type]['heading']['#value'] = format_plural(count($config_names), '@count new', '@count new'); break; case 'update': $form[$collection][$config_change_type]['heading']['#value'] = format_plural(count($config_names), '@count changed', '@count changed'); break; case 'delete': $form[$collection][$config_change_type]['heading']['#value'] = format_plural(count($config_names), '@count removed', '@count removed'); break; case 'rename': $form[$collection][$config_change_type]['heading']['#value'] = format_plural(count($config_names), '@count renamed', '@count renamed'); break; } $form[$collection][$config_change_type]['list'] = array('#type' => 'table', '#header' => array('Name', 'Operations')); foreach ($config_names as $config_name) { if ($config_change_type == 'rename') { $names = $storage_comparer->extractRenameNames($config_name); $route_options = array('source_name' => $names['old_name'], 'target_name' => $names['new_name']); $config_name = $this->t('!source_name to !target_name', array('!source_name' => $names['old_name'], '!target_name' => $names['new_name'])); } else { $route_options = array('source_name' => $config_name); } if ($collection != StorageInterface::DEFAULT_COLLECTION) { $route_name = 'config.diff_collection'; $route_options['collection'] = $collection; } else { $route_name = 'config.diff'; } $links['view_diff'] = array('title' => $this->t('View differences'), 'url' => Url::fromRoute($route_name, $route_options), 'attributes' => array('class' => array('use-ajax'), 'data-accepts' => 'application/vnd.drupal-modal', 'data-dialog-options' => json_encode(array('width' => 700)))); $form[$collection][$config_change_type]['list']['#rows'][] = array('name' => $config_name, 'operations' => array('data' => array('#type' => 'operations', '#links' => $links))); } } } return $form; }
/** * {@inheritdoc} */ public function createSnapshot(StorageInterface $source_storage, StorageInterface $snapshot_storage) { // Empty the snapshot of all configuration. $snapshot_storage->deleteAll(); foreach ($snapshot_storage->getAllCollectionNames() as $collection) { $snapshot_collection = $snapshot_storage->createCollection($collection); $snapshot_collection->deleteAll(); } foreach ($source_storage->listAll() as $name) { $snapshot_storage->write($name, $source_storage->read($name)); } // Copy collections as well. foreach ($source_storage->getAllCollectionNames() as $collection) { $source_collection = $source_storage->createCollection($collection); $snapshot_collection = $snapshot_storage->createCollection($collection); foreach ($source_collection->listAll() as $name) { $snapshot_collection->write($name, $source_collection->read($name)); } } }
/** * Tests that default config matches the installed config. * * @param \Drupal\Core\Config\StorageInterface $default_config_storage * The default config storage to test. */ protected function doTestsOnConfigStorage(StorageInterface $default_config_storage) { /** @var \Drupal\Core\Config\ConfigManagerInterface $config_manager */ $config_manager = $this->container->get('config.manager'); // Just connect directly to the config table so we don't need to worry about // the cache layer. $active_config_storage = $this->container->get('config.storage'); foreach ($default_config_storage->listAll() as $config_name) { if ($active_config_storage->exists($config_name)) { // If it is a config entity re-save it. This ensures that any // recalculation of dependencies does not cause config change. if ($entity_type = $config_manager->getEntityTypeIdByName($config_name)) { $entity_storage = $config_manager->getEntityManager()->getStorage($entity_type); $id = $entity_storage->getIDFromConfigName($config_name, $entity_storage->getEntityType()->getConfigPrefix()); $entity_storage->load($id)->calculateDependencies()->save(); } $result = $config_manager->diff($default_config_storage, $active_config_storage, $config_name); $this->assertConfigDiff($result, $config_name, static::$skippedConfig); } } }