From 482651db1f5e94cfaf6f31e72bf541eee715fce8 Mon Sep 17 00:00:00 2001 From: Marcelo Vani Date: Wed, 25 Jan 2017 12:03:11 +0000 Subject: [PATCH 1/3] Applied patch 2829614 --- domain_config_ui/README.md | 9 + domain_config_ui/domain_config_ui.info.yml | 8 + domain_config_ui/domain_config_ui.module | 166 +++++++++++++++++ .../domain_config_ui.services.yml | 16 ++ domain_config_ui/src/Config/Config.php | 68 +++++++ domain_config_ui/src/Config/ConfigFactory.php | 162 ++++++++++++++++ .../src/DomainConfigUIManager.php | 176 ++++++++++++++++++ domain_config_ui/src/Form/SwitchForm.php | 113 +++++++++++ 8 files changed, 718 insertions(+) create mode 100644 domain_config_ui/README.md create mode 100644 domain_config_ui/domain_config_ui.info.yml create mode 100644 domain_config_ui/domain_config_ui.module create mode 100644 domain_config_ui/domain_config_ui.services.yml create mode 100644 domain_config_ui/src/Config/Config.php create mode 100644 domain_config_ui/src/Config/ConfigFactory.php create mode 100644 domain_config_ui/src/DomainConfigUIManager.php create mode 100644 domain_config_ui/src/Form/SwitchForm.php diff --git a/domain_config_ui/README.md b/domain_config_ui/README.md new file mode 100644 index 00000000..b94b52ed --- /dev/null +++ b/domain_config_ui/README.md @@ -0,0 +1,9 @@ +Domain Config UI +================ + +This module allows configuration to be saved for a selected domain. + +Dependencies +============ + +- Domain Config diff --git a/domain_config_ui/domain_config_ui.info.yml b/domain_config_ui/domain_config_ui.info.yml new file mode 100644 index 00000000..2e4c9df0 --- /dev/null +++ b/domain_config_ui/domain_config_ui.info.yml @@ -0,0 +1,8 @@ +name: Domain Configuration UI +description: 'Allows saving of domain specific configuration through the UI.' +type: module +package: Domain +version: VERSION +core: 8.x +dependencies: + - domain_config diff --git a/domain_config_ui/domain_config_ui.module b/domain_config_ui/domain_config_ui.module new file mode 100644 index 00000000..64b9eb44 --- /dev/null +++ b/domain_config_ui/domain_config_ui.module @@ -0,0 +1,166 @@ +getForm('Drupal\domain_config_ui\Form\SwitchForm'); + $content = [ + 'domain_config_ui_switch' => $form, + ]; + + $variables['page']['content'] = array_merge($content, $variables['page']['content']); + + // Add a message below the form to remind the administrator which domain they are currently configuring. + if ($warning_message = domain_config_ui_save_warning_message()) { + $variables['page']['content']['domain_config_ui_switch_warning'] = $warning_message; + } +} + +/** + * Implements hook_form_alter(). + * + * @param array $form + * @param FormStateInterface $form_state + */ +function domain_config_ui_form_alter(&$form, FormStateInterface $form_state) { + // Only alter config forms that can have a config factory and are on an admin path. + if (!domain_config_ui_route_is_admin() || !domain_config_ui_form_is_allowed($form)) { + return; + } + + // Create fieldset to group domain fields. + $form['domain_config_ui'] = [ + '#type' => 'fieldset', + '#title' => 'Domain Configuration', + '#weight' => -10, + ]; + + // Add domain switch select field. + $selected_domain = \Drupal::service('domain_config_ui.manager')->getSelectedDomain(); + $form['domain_config_ui']['config_save_domain'] = [ + '#type' => 'select', + '#title' => 'Domain', + '#options' => array_merge(['' => 'All Domains'], \Drupal::service('domain.loader')->loadOptionsList()), + '#default_value' => $selected_domain ? $selected_domain->id() : '', + '#ajax' => [ + 'callback' => 'domain_config_ui_domain_switch_form_callback', + ], + ]; + + // Add language select field. + $selected_language = \Drupal::service('domain_config_ui.manager')->getSelectedLanguage(); + $language_options = ['' => 'Default']; + foreach (\Drupal::languageManager()->getLanguages() as $id => $language) { + $language_options[$id] = $language->getName(); + } + $form['domain_config_ui']['config_save_language'] = [ + '#type' => 'select', + '#title' => 'Language', + '#options' => $language_options, + '#default_value' => $selected_language ? $selected_language->getId() : '', + '#ajax' => [ + 'callback' => 'domain_config_ui_domain_switch_form_callback', + ], + ]; + + // Add a message below the form to remind the administrator which domain they are currently configuring. + if ($warning_message = domain_config_ui_save_warning_message()) { + $form['domain_message'] = $warning_message; + } +} + +/** + * Helper to generate the markup for the domain save warning message. + */ +function domain_config_ui_save_warning_message() { + $selected_domain = \Drupal::service('domain_config_ui.manager')->getSelectedDomain(); + if ($selected_domain) { + $selected_language = \Drupal::service('domain_config_ui.manager')->getSelectedLanguage(); + $message = new TranslatableMarkup('Configuration will be saved for @domain @language', [ + '@domain' => $selected_domain->label(), + '@language' => $selected_language ? '(' . $selected_language->getName() . ')' : '', + ]); + return [ + '#markup' => new FormattableMarkup('
@message
', [ + '@message' => $message, + ]), + '#weight' => 1000, + ]; + } +} + +/** + * Checks if provided form can be used to save domain specic configuration. + * + * @param array $form + * @return boolean + */ +function domain_config_ui_form_is_allowed($form) { + $allowed = [ + 'system_site_information_settings', + 'system_theme_settings', + ]; + \Drupal::moduleHandler()->alter('domain_config_form_allowed', $allowed); + return in_array($form['#form_id'], $allowed); +} + +/** + * Checks if provided path should have a domain switch form added to the top of the page. + * + * @return boolean + */ +function domain_config_ui_route_is_allowed() { + $allowed = [ + '/admin/appearance', + ]; + \Drupal::moduleHandler()->alter('domain_config_route_allowed', $allowed); + $route = \Drupal::routeMatch()->getRouteObject(); + return in_array($route->getPath(), $allowed); +} + +/** + * Checks if route is admin. + * + * @return boolean + */ +function domain_config_ui_route_is_admin() { + $route = \Drupal::routeMatch()->getRouteObject(); + return \Drupal::service('router.admin_context')->isAdminRoute($route); +} + +/** + * AJAX callback to set the current domain. + * + * @param array $form + * @param FormStateInterface $form_state + */ +function domain_config_ui_domain_switch_form_callback($form, FormStateInterface $form_state) { + // Switch the current domain. + \Drupal::service('domain_config_ui.manager')->setSelectedDomain($form_state->getValue('config_save_domain')); + + // Switch the current language. + \Drupal::service('domain_config_ui.manager')->setSelectedLanguage($form_state->getValue('config_save_language')); + + // Reset form with selected domain configuration. + $form_state->setUserInput([]); + $new_form = \Drupal::formBuilder()->rebuildForm($form['#form_id'], $form_state, $form); + $response = new AjaxResponse(); + $response->addCommand(new ReplaceCommand('.' . str_replace('_', '-', $form['#form_id']), $new_form)); + return $response; +} diff --git a/domain_config_ui/domain_config_ui.services.yml b/domain_config_ui/domain_config_ui.services.yml new file mode 100644 index 00000000..361fac97 --- /dev/null +++ b/domain_config_ui/domain_config_ui.services.yml @@ -0,0 +1,16 @@ +services: + domain_config_ui.manager: + class: Drupal\domain_config_ui\DomainConfigUIManager + arguments: ['@config.storage', '@domain.loader', '@language_manager'] + + domain_config_ui.factory: + class: Drupal\domain_config_ui\Config\ConfigFactory + tags: + - { name: event_subscriber } + - { name: service_collector, tag: 'config.factory.override', call: addOverride } + arguments: ['@config.storage', '@event_dispatcher', '@config.typed'] + calls: + - [setDomainConfigUIManager, ['@domain_config_ui.manager']] + + config.factory: + alias: domain_config_ui.factory diff --git a/domain_config_ui/src/Config/Config.php b/domain_config_ui/src/Config/Config.php new file mode 100644 index 00000000..b9990a0d --- /dev/null +++ b/domain_config_ui/src/Config/Config.php @@ -0,0 +1,68 @@ +domainConfigUIManager = $domain_config_ui_manager; + } + + /** + * {@inheritdoc} + */ + public function save($has_trusted_data = FALSE) { + // Remember original config name. + $originalName = $this->name; + + try { + // Get domain config name for saving. + $domainConfigName = $this->getDomainConfigName(); + + // If config is new and we are currently saving domain specific configuration, + // save with original name first so that there is always a default configuration. + if ($this->isNew && $domainConfigName != $originalName) { + parent::save($has_trusted_data); + } + + // Switch to use domain config name and save. + $this->name = $domainConfigName; + parent::save($has_trusted_data); + } + catch (\Exception $e) { + // Reset back to original config name if save fails and re-throw. + $this->name = $originalName; + throw $e; + } + + // Reset back to original config name after saving. + $this->name = $originalName; + + return $this; + } + + /** + * Get the domain config name. + */ + protected function getDomainConfigName() { + // Return selected config name. + return $this->domainConfigUIManager->getSelectedConfigName($this->name); + } + +} diff --git a/domain_config_ui/src/Config/ConfigFactory.php b/domain_config_ui/src/Config/ConfigFactory.php new file mode 100644 index 00000000..131b16c6 --- /dev/null +++ b/domain_config_ui/src/Config/ConfigFactory.php @@ -0,0 +1,162 @@ +allowedDomainConfig; + \Drupal::moduleHandler()->alter('domain_config_allowed', $allowed); + + // Return original name if reserved not allowed. + $is_allowed = FALSE; + foreach ($allowed as $config_name) { + // Convert config_name into into regex. + // Escapes regex syntax, but keeps * wildcards. + $pattern = '/^' . str_replace('\*', '.*', preg_quote($config_name, '/')) . '$/'; + if (preg_match($pattern, $name)) { + $is_allowed = TRUE; + } + } + + return $is_allowed; + } + + /** + * {@inheritDoc} + * @see \Drupal\Core\Config\ConfigFactory::createConfigObject() + */ + protected function createConfigObject($name, $immutable) { + if (!$immutable && $this->isAllowedDomainConfig($name)) { + $config = new Config($name, $this->storage, $this->eventDispatcher, $this->typedConfigManager); + // Pass the UI manager to the Config object. + $config->setDomainConfigUIManager($this->domainConfigUIManager); + return $config; + } + return parent::createConfigObject($name, $immutable); + } + + /** + * Set the Domain config UI manager. + * + * @param DomainConfigUIManager $domain_config_ui_manager + */ + public function setDomainConfigUIManager($domain_config_ui_manager) { + $this->domainConfigUIManager = $domain_config_ui_manager; + } + + /** + * {@inheritDoc} + * @see \Drupal\Core\Config\ConfigFactory::doLoadMultiple() + */ + protected function doLoadMultiple(array $names, $immutable = TRUE) { + // Let parent load multiple load as usual. + $list = parent::doLoadMultiple($names, $immutable); + + // Do not apply overrides if configuring 'all' domains or config is immutable. + if (empty($this->domainConfigUIManager) || !$this->domainConfigUIManager->getSelectedDomainId() || !$this->isAllowedDomainConfig(current($names))) { + return $list; + } + + // Pre-load remaining configuration files. + if (!empty($names)) { + // Initialise override information. + $module_overrides = []; + $storage_data = $this->storage->readMultiple($names); + + // Load module overrides so that domain specific config is loaded in admin forms. + if (!empty($storage_data)) { + // Only get domain overrides if we have configuration to override. + $module_overrides = $this->loadDomainOverrides($names); + } + + foreach ($storage_data as $name => $data) { + $cache_key = $this->getConfigCacheKey($name, $immutable); + + if (isset($module_overrides[$name])) { + $this->cache[$cache_key]->setModuleOverride($module_overrides[$name]); + $list[$name] = $this->cache[$cache_key]; + } + + $this->propagateConfigOverrideCacheability($cache_key, $name); + } + } + + return $list; + } + + /** + * {@inheritDoc} + * @see \Drupal\Core\Config\ConfigFactory::doGet() + */ + protected function doGet($name, $immutable = TRUE) { + // Do not apply overrides if configuring 'all' domains or config is immutable. + if (empty($this->domainConfigUIManager) || !$this->domainConfigUIManager->getSelectedDomainId() || !$this->isAllowedDomainConfig($name)) { + return parent::doGet($name, $immutable); + } + + if ($config = $this->doLoadMultiple([$name], $immutable)) { + return $config[$name]; + } + else { + // If the configuration object does not exist in the configuration + // storage, create a new object. + $config = $this->createConfigObject($name, $immutable); + + // Load domain overrides so that domain specific config is loaded in admin forms. + $overrides = $this->loadDomainOverrides([$name]); + if (isset($overrides[$name])) { + $config->setModuleOverride($overrides[$name]); + } + + foreach ($this->configFactoryOverrides as $override) { + $config->addCacheableDependency($override->getCacheableMetadata($name)); + } + + return $config; + } + } + + /** + * Get arbitrary overrides for the named configuration objects from Domain module. + * + * @param array $names + * The names of the configuration objects to get overrides for. + * + * @return array + * An array of overrides keyed by the configuration object name. + */ + protected function loadDomainOverrides(array $names) { + return $this->domainConfigUIManager->loadOverrides($names); + } +} diff --git a/domain_config_ui/src/DomainConfigUIManager.php b/domain_config_ui/src/DomainConfigUIManager.php new file mode 100644 index 00000000..b031a681 --- /dev/null +++ b/domain_config_ui/src/DomainConfigUIManager.php @@ -0,0 +1,176 @@ +storage = $storage; + $this->domainLoader = $domain_loader; + $this->languageManager = $language_manager; + + // Get the language context. + if ($language = $this->getSelectedLanguage()) { + $this->language = $language; + } + + // Get the domain context. + if ($domain = $this->getSelectedDomain()) { + $this->domain = $domain; + } + } + + /** + * Load only overrides for selected domain and language. + */ + public function loadOverrides($names) { + $overrides = []; + if (!empty($this->domain)) { + foreach ($names as $name) { + $config_name = $this->getSelectedConfigName($name); + if ($override = $this->storage->read($config_name)) { + $overrides[$name] = $override; + } + } + } + return $overrides; + } + + /** + * Get selected config name. + * @param string $name + */ + public function getSelectedConfigName($name) { + // Build prefix and add to front of existing key. + if ($selected_domain = $this->getSelectedDomain()) { + $prefix = 'domain.config.' . $selected_domain->id() . '.'; + // Add selected language. + if ($language = $this->getSelectedLanguage()) { + $prefix .= $language->getId() . '.'; + } + $name = $prefix . $name; + } + return $name; + } + + /** + * Get the selected domain. + */ + public function getSelectedDomain() { + $selected_domain_id = $this->getSelectedDomainId(); + if ($selected_domain_id && $selected_domain = $this->domainLoader->load($selected_domain_id)) { + return $selected_domain; + } + } + + /** + * Get the selected domain ID. + */ + public function getSelectedDomainId() { + return !empty($_SESSION['domain_config_ui']['config_save_domain']) ? $_SESSION['domain_config_ui']['config_save_domain'] : ''; + } + + /** + * Set the current selected domain ID. + * @param string $domain_id + */ + public function setSelectedDomain($domain_id) { + if ($domain = $this->domainLoader->load($domain_id)) { + // Set session for subsequent request. + $_SESSION['domain_config_ui']['config_save_domain'] = $domain_id; + // Switch active domain now so that selected domain configuration can be loaded immediatly. + // This is primarily for switching domain with AJAX request. + $this->domain = $domain; + } + else { + $_SESSION['domain_config_ui']['config_save_domain'] = ''; + unset($this->domain); + } + } + + /** + * Set the selected language. + * @param string $language_id + */ + public function setSelectedLanguage($language_id) { + if ($language = $this->languageManager->getLanguage($language_id)) { + // Set session for subsequent request. + $_SESSION['domain_config_ui']['config_save_language'] = $language_id; + // Switch active language now so that selected domain configuration can be loaded immediatly. + // This is primarily for switching domain with AJAX request. + $this->language = $language; + } + else { + $_SESSION['domain_config_ui']['config_save_language'] = ''; + unset($this->language); + } + } + + /** + * Get the selected language ID. + */ + public function getSelectedLanguageId() { + return !empty($_SESSION['domain_config_ui']['config_save_language']) ? $_SESSION['domain_config_ui']['config_save_language'] : ''; + } + + /** + * Get the selected language. + */ + public function getSelectedLanguage() { + $selected_language_id = $this->getSelectedLanguageId(); + if ($selected_language_id && $selected_language = $this->languageManager->getLanguage($selected_language_id)) { + return $selected_language; + } + } +} diff --git a/domain_config_ui/src/Form/SwitchForm.php b/domain_config_ui/src/Form/SwitchForm.php new file mode 100644 index 00000000..04f8b0fb --- /dev/null +++ b/domain_config_ui/src/Form/SwitchForm.php @@ -0,0 +1,113 @@ +currentUser()->hasPermission('administer domains'); + $form = $this->addSwitchFields($form, $form_state); + return $form; + } + + /** + * Helper to add switch fields to form. + * + * @param array $form + * @param FormStateInterface $form_state + */ + public function addSwitchFields(array $form, FormStateInterface $form_state) { + // Create fieldset to group domain fields. + $form['domain_config_ui'] = [ + '#type' => 'fieldset', + '#title' => 'Domain Configuration', + '#weight' => -10, + ]; + + // Add domain switch select field. + $selected_domain = \Drupal::service('domain_config_ui.manager')->getSelectedDomain(); + $form['domain_config_ui']['config_save_domain'] = [ + '#type' => 'select', + '#title' => 'Domain', + '#options' => array_merge(['' => 'All Domains'], \Drupal::service('domain.loader')->loadOptionsList()), + '#default_value' => $selected_domain ? $selected_domain->id() : '', + '#ajax' => [ + 'callback' => '::switchCallback', + ], + ]; + + // Add language select field. + $selected_language = \Drupal::service('domain_config_ui.manager')->getSelectedLanguage(); + $language_options = ['' => 'Default']; + foreach (\Drupal::languageManager()->getLanguages() as $id => $language) { + $language_options[$id] = $language->getName(); + } + $form['domain_config_ui']['config_save_language'] = [ + '#type' => 'select', + '#title' => 'Language', + '#options' => $language_options, + '#default_value' => $selected_language ? $selected_language->getId() : '', + '#ajax' => [ + 'callback' => '::switchCallback', + ], + ]; + + return $form; + } + + /** + * {@inheritDoc} + */ + public function submitForm(array &$form, FormStateInterface $form_state) { + // Form does not require submit handler. + } + + /** + * Callback to remember save mode and reload page. + * + * @param array $form + * @param FormStateInterface $form_state + */ + public static function switchCallback(array &$form, FormStateInterface $form_state) { + // Switch the current domain. + \Drupal::service('domain_config_ui.manager')->setSelectedDomain($form_state->getValue('config_save_domain')); + + // Switch the current language. + \Drupal::service('domain_config_ui.manager')->setSelectedLanguage($form_state->getValue('config_save_language')); + + // Extract requesting page URI from ajax URI. + // Copied from Drupal\Core\Form\FormBuilder::buildFormAction(). + $request_uri = \Drupal::service('request_stack')->getMasterRequest()->getRequestUri(); + + // Prevent cross site requests via the Form API by using an absolute URL + // when the request uri starts with multiple slashes. + if (strpos($request_uri, '//') === 0) { + $request_uri = $request->getUri(); + } + + $parsed = UrlHelper::parse($request_uri); + unset($parsed['query']['ajax_form'], $parsed['query'][MainContentViewSubscriber::WRAPPER_FORMAT]); + $request_uri = $parsed['path'] . ($parsed['query'] ? ('?' . UrlHelper::buildQuery($parsed['query'])) : ''); + + // Reload the page to get new form values. + $response = new AjaxResponse(); + $response->addCommand(new RedirectCommand($request_uri)); + return $response; + } +} From 00c34d181d3201513cb8f518bc435363ceeac8e1 Mon Sep 17 00:00:00 2001 From: Marcelo Vani Date: Fri, 27 Jan 2017 18:07:37 +0000 Subject: [PATCH 2/3] Added missing dependency --- domain_access/domain_access.info.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/domain_access/domain_access.info.yml b/domain_access/domain_access.info.yml index bf969c9b..49270f82 100644 --- a/domain_access/domain_access.info.yml +++ b/domain_access/domain_access.info.yml @@ -5,4 +5,5 @@ package: Domain version: VERSION core: 8.x dependencies: + - node - domain From 708858cd3ed0a9a83057a009e8ffef629557c8b7 Mon Sep 17 00:00:00 2001 From: Marcelo Vani Date: Mon, 30 Jan 2017 12:00:50 +0000 Subject: [PATCH 3/3] Fixed array --- domain/domain.module | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain/domain.module b/domain/domain.module index 95e30ef1..6ba0b0d2 100644 --- a/domain/domain.module +++ b/domain/domain.module @@ -138,7 +138,7 @@ function domain_confirm_fields($entity_type, $bundle, $handler = 'default:domain 'id' => $storage_id, 'field_name' => DOMAIN_ADMIN_FIELD, 'type' => 'entity_reference', - 'dependencies' => 'domain' , 'user', + 'dependencies' => array('domain' , 'user'), 'entity_type' => 'user', 'cardinality' => -1, 'module' => 'entity_reference',