diff --git a/config_ignore.api.php b/config_ignore.api.php index 89e9f91..1054e84 100644 --- a/config_ignore.api.php +++ b/config_ignore.api.php @@ -18,6 +18,13 @@ function hook_config_ignore_settings_alter(array &$settings) { $settings[] = 'field.*'; } +/** + * Alter the list of config entities that should be ignored. + */ +function hook_config_ignore_collections_alter(array &$collections) { + $collections[] = 'language.*'; +} + /** * @} End of "addtogroup hooks". */ diff --git a/config_ignore.install b/config_ignore.install index 80534e2..00f6e92 100644 --- a/config_ignore.install +++ b/config_ignore.install @@ -21,3 +21,11 @@ function config_ignore_update_8202() { $config->set('ignored_config_entities', array_values($ignored_config_entities)); $config->save(); } + +/** + * Update schema with storage collection ignore value. + */ +function config_ignore_update_8203() { + $config = \Drupal::configFactory()->getEditable('config_ignore.settings'); + $config->set('ignored_config_collections', [])->save(); +} diff --git a/src/EventSubscriber/ConfigIgnoreEventSubscriber.php b/src/EventSubscriber/ConfigIgnoreEventSubscriber.php index 4aa1fdb..d75e994 100644 --- 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. * diff --git a/src/Form/Settings.php b/src/Form/Settings.php index d5b6baa..f453ba9 100644 --- a/src/Form/Settings.php +++ b/src/Form/Settings.php @@ -54,6 +54,16 @@ Examples: