reverted: --- b/config/install/config_ignore.settings.yml +++ a/config/install/config_ignore.settings.yml @@ -1,2 +1 @@ ignored_config_entities: { } -ignored_config_collections: { } reverted: --- b/config/schema/config_ignore.schema.yml +++ a/config/schema/config_ignore.schema.yml @@ -7,8 +7,3 @@ label: 'List of ignored configurations' sequence: type: string - ignored_config_collections: - type: sequence - label: 'List of ignored configuration storage collections' - sequence: - type: string diff -u b/config_ignore.install b/config_ignore.install --- b/config_ignore.install +++ b/config_ignore.install @@ -15,17 +15,17 @@ /** - * Update schema with storage collection ignore value. + * Remove index from configuration export. */ -function config_ignore_update_8203() { +function config_ignore_update_8202() { $config = \Drupal::configFactory()->getEditable('config_ignore.settings'); - $config->set('ignored_config_collections', [])->save(); + $ignored_config_entities = $config->get('ignored_config_entities') ?: []; + $config->set('ignored_config_entities', array_values($ignored_config_entities)); + $config->save(); } /** - * Remove index from configuration export. + * Update schema with storage collection ignore value. */ -function config_ignore_update_8204() { +function config_ignore_update_8203() { $config = \Drupal::configFactory()->getEditable('config_ignore.settings'); - $ignored_config_entities = $config->get('ignored_config_entities') ?: []; - $config->set('ignored_config_entities', array_values($ignored_config_entities)); - $config->save(); + $config->set('ignored_config_collections', [])->save(); } diff -u b/src/Form/Settings.php b/src/Form/Settings.php --- b/src/Form/Settings.php +++ b/src/Form/Settings.php @@ -71,18 +71,26 @@ * {@inheritdoc} */ public function submitForm(array &$form, FormStateInterface $form_state) { + $values = $form_state->getValues(); $config_ignore_settings = $this->config('config_ignore.settings'); // Normalize the text to Unix line endings. - $ignored_config_entities = str_replace("\r", "\n", $form_state->getValue('ignored_config_entities')); - $config_ignore_settings_array = array_values( + $ignored_config_entities = str_replace("\r", "\n", $values['ignored_config_entities']); + $config_ignore_entities_array = array_values( array_filter( array_map('trim', explode("\n", $ignored_config_entities)) ) ); - $config_ignore_settings->set('ignored_config_entities', $config_ignore_settings_array); - $config_collection_storage_array = preg_split("[\n|\r]", $values['ignored_config_collections']); - $config_collection_storage_array = array_filter($config_collection_storage_array); - $config_ignore_settings->set('ignored_config_collections', $config_collection_storage_array); + $config_ignore_settings->set('ignored_config_entities', $config_ignore_entities_array); + $config_ignore_settings->save(); + + // Normalize the text to Unix line endings. + $ignored_config_collections = str_replace("\r", "\n", $values['ignored_config_collections']); + $config_ignore_collections_array = array_values( + array_filter( + array_map('trim', explode("\n", $ignored_config_collections)) + ) + ); + $config_ignore_settings->set('ignored_config_collections', $config_ignore_collections_array); $config_ignore_settings->save(); parent::submitForm($form, $form_state); } reverted: --- b/src/Plugin/ConfigFilter/CollectionIgnore.php +++ /dev/null @@ -1,87 +0,0 @@ -get('config.factory') - ->get('config_ignore.settings') - ->get('ignored_config_collections') ?: []; - // Allow hooks to alter the list. - $container->get('module_handler') - ->invokeAll('config_ignore_collections_alter', [&$ignored_collections]); - // Set the list in the plugin configuration. - $configuration['ignored_collections'] = $ignored_collections; - - return new static( - $configuration, - $plugin_id, - $plugin_definition - ); - } - - /** - * Match a storage collection name against list of ignored collections. - * - * @param string $collection_name - * The name of the collection to match against all ignored collections. - * - * @return bool - * True, if the storage collection is to be ignored, false otherwise. - */ - protected function matchCollectionName($collection_name) { - if (Settings::get('config_ignore_deactivate')) { - // Allow deactivating config_ignore in settings.php. Do not match any name - // in that case and allow a normal configuration import to happen. - return FALSE; - } - - // If the string is an excluded collection, don't ignore it. - if (in_array(static::FORCE_EXCLUSION_PREFIX . $collection_name, $this->configuration['ignored_collections'], TRUE)) { - return FALSE; - } - - foreach ($this->configuration['ignored_collections'] as $ignored) { - if (fnmatch($ignored, $collection_name)) { - return TRUE; - } - } - - return FALSE; - } - - /** - * {@inheritdoc} - */ - public function filterGetAllCollectionNames(array $collections) { - $collections = array_filter($collections, function ($collection) { - return !$this->matchCollectionName($collection); - }); - return $collections; - } - -} only in patch2: unchanged: --- a/src/EventSubscriber/ConfigIgnoreEventSubscriber.php +++ b/src/EventSubscriber/ConfigIgnoreEventSubscriber.php @@ -106,15 +106,33 @@ class ConfigIgnoreEventSubscriber implements EventSubscriberInterface { * The active storage on import. The sync storage on export. */ protected function transformStorage(StorageInterface $transformation_storage, StorageInterface $destination_storage) { - $ignored_configs = $this->getIgnoredConfigs($transformation_storage); + $ignored_configs = $this->getIgnoredConfigs(); - $collection_names = $transformation_storage->getAllCollectionNames(); + // Fetching collection names common to both the storages. + $collection_names = array_unique(array_merge($transformation_storage->getAllCollectionNames(), $destination_storage->getAllCollectionNames())); array_unshift($collection_names, StorageInterface::DEFAULT_COLLECTION); + $ignored_collections = array_keys($this->getIgnoredCollections($collection_names)); + foreach ($collection_names as $collection_name) { + $destination_storage = $destination_storage->createCollection($collection_name); $transformation_storage = $transformation_storage->createCollection($collection_name); + if (in_array($collection_name, $ignored_collections)) { + foreach ($this->configFactory->listAll() as $config_name) { + $collection_source_data = $destination_storage->read($config_name); + + if(is_array($collection_source_data) && count(array_filter($collection_source_data)) != 0) { + $transformation_storage->write($config_name, $destination_storage->read($config_name)); + } + else { + $transformation_storage->delete($config_name); + } + } + continue; + } + foreach ($ignored_configs as $config_name => $keys) { if ($destination_storage->exists($config_name)) { // The entire config is ignored. @@ -146,10 +164,12 @@ class ConfigIgnoreEventSubscriber implements EventSubscriberInterface { // Only some keys are ignored. else { $source_data = $transformation_storage->read($config_name); - foreach ($keys as $key) { - NestedArray::unsetValue($source_data, $key); + if(is_array($source_data)) { + foreach ($keys as $key) { + NestedArray::unsetValue($source_data, $key); + } + $transformation_storage->write($config_name, $source_data); } - $transformation_storage->write($config_name, $source_data); } } } @@ -227,6 +247,76 @@ class ConfigIgnoreEventSubscriber implements EventSubscriberInterface { return array_diff_key($ignored_configs, array_flip($exceptions)); } + /** + * Returns the list of all ignored collections by expanding the wildcards. + * + * @param array $collection_names + * An array of existing collection names. + * @return array + * An associative array keyed by collection name and having the values either + * NULL, if the whole config is ignored, or an array of keys to be ignored. + * Each key is an array of parents: + * @code + * [ + * 'system.site' => NULL, + * 'user.settings' => [ + * ['notify', 'cancel_confirm'], + * ['password_reset_timeout'], + * ], + * ] + * @endcode + */ + protected function getIgnoredCollections(array $collection_names) { + /** @var string[] $ignored_collections_patterns */ + $ignored_collections_patterns = $this->configFactory->get('config_ignore.settings')->get('ignored_config_collections'); + $this->moduleHandler->invokeAll('config_ignore_collections_alter', [&$ignored_collections_patterns]); + + // Builds ignored collections exceptions and remove them from the pattern list. + $exceptions = []; + foreach ($ignored_collections_patterns as $delta => $ignored_collection_pattern) { + if (strpos($ignored_collection_pattern, '~') === 0) { + if (strpos($ignored_collection_pattern, '*') !== FALSE) { + throw new \LogicException("A collection ignore pattern entry cannot contain both, '~' and '*'."); + } + $exceptions[] = substr($ignored_collection_pattern, 1); + unset($ignored_collections_patterns[$delta]); + } + } + + $ignored_collections = []; + foreach ($collection_names as $collection_name) { + foreach ($ignored_collections_patterns as $ignored_collection_pattern) { + if (strpos($ignored_collection_pattern, ':') !== FALSE) { + // Some patterns are defining also a key. + [$collection_name_pattern, $key] = explode(':', $ignored_collection_pattern, 2); + $key = trim($key); + if (strpos($key, '*') !== FALSE) { + throw new \LogicException("The key part of the config ignore pattern cannot contain the wildcard character '*'."); + } + } + else { + $collection_name_pattern = $ignored_collection_pattern; + $key = NULL; + } + if ($this->wildcardMatch($collection_name_pattern, $collection_name)) { + if ($key) { + $ignored_collections[$collection_name][] = explode('.', $key); + } + else { + $ignored_collections[$collection_name] = NULL; + // As this pattern has no key we continue with the next config. Any + // subsequent pattern with the same config but with key is covered + // by this ignore pattern. + break; + } + } + } + } + + // Extract the exceptions from the ignored configs. + return array_diff_key($ignored_collections, array_flip($exceptions)); + } + /** * Checks if a string matches a given wildcard pattern. *