diff --git a/README.txt b/README.txt index 9d803fe..2919fd4 100644 --- a/README.txt +++ b/README.txt @@ -10,7 +10,14 @@ To set a site in read-only mode add this to setting.php: $settings['config_readonly'] = TRUE; To provide a whitelist of configuration that can be changed when in read-only -mode implement the hook: +mode add this to settings.php: + + $settings['config_readonly_whitelist_patterns'] = [ + 'config_name.to.ignore', + 'wildcards*allowed', + ]; + +Or implement the hook: hook_config_readonly_whitelist_patterns() { return [ diff --git a/config_readonly.module b/config_readonly.module index b8d8cb7..1e00f43 100644 --- a/config_readonly.module +++ b/config_readonly.module @@ -35,3 +35,10 @@ function config_readonly_form_alter(array &$form, FormStateInterface &$form_stat function _config_readonly_validate_failure(array $form, FormStateInterface &$form_state) { $form_state->setErrorByName(NULL, t('This configuration form cannot be saved because the configuration active store is read-only.')); } + +/** + * Implements hook_config_readonly_whitelist_patterns(). + */ +function config_readonly_config_readonly_whitelist_patterns() { + return Settings::get('config_readonly_whitelist_patterns'); +} diff --git a/src/EventSubscriber/ReadOnlyFormSubscriber.php b/src/EventSubscriber/ReadOnlyFormSubscriber.php index da35a61..85554fe 100644 --- a/src/EventSubscriber/ReadOnlyFormSubscriber.php +++ b/src/EventSubscriber/ReadOnlyFormSubscriber.php @@ -73,23 +73,8 @@ class ReadOnlyFormSubscriber implements EventSubscriberInterface { } if ($mark_form_read_only && $form_object instanceof ConfigFormBase) { - - // This is a dirty hack to access the editable configuration. - // Look away! - $editable_config_names_hack = function (ConfigFormBase $config_form) { - // The getEditableConfigNames is part of the public api or Drupal 8. - // Since it will always remain private (as making it public in core - // would break all implementations) it will have to be called - // with a different name, or with this workaround. - $reflection = new \ReflectionMethod(get_class($config_form), 'getEditableConfigNames'); - $reflection->setAccessible(TRUE); - return $reflection->invoke($config_form); - }; - - // Hopefully this will not be needed some day. - // See https://www.drupal.org/node/2095289 - // $editable_config = $form_object->ConfigNames(); - $editable_config = $editable_config_names_hack($form_object); + // Get the editable configuration names. + $editable_config = $this->getEditableConfigNames($form_object); // If all editable config is in the whitelist, do not block the form. if ($editable_config == array_filter($editable_config, [$this, 'matchesWhitelistPattern'])) { @@ -117,4 +102,25 @@ class ReadOnlyFormSubscriber implements EventSubscriberInterface { return $events; } + /** + * Get the editable configuration names. + * + * @param ConfigFormBase $form + * The configuration form. + * + * @return array + * An array of configuration object names that are editable if called in + * conjunction with the trait's config() method. + * + * @see ConfigFormBaseTrait::getEditableConfigNames() + */ + protected function getEditableConfigNames(ConfigFormBase $form) { + // Use reflection to work around getEditableConfigNames() as protected. + // @todo Review in 9.x for API change. + // @see https://www.drupal.org/node/2095289 + $reflection = new \ReflectionMethod(get_class($form), 'getEditableConfigNames'); + $reflection->setAccessible(TRUE); + return $reflection->invoke($form); + } + }