Backup of db before drupal security update
[yaffs-website] / web / core / modules / config_translation / src / Form / ConfigTranslationFormBase.php
1 <?php
2
3 namespace Drupal\config_translation\Form;
4
5 use Drupal\config_translation\ConfigMapperManagerInterface;
6 use Drupal\Core\Config\TypedConfigManagerInterface;
7 use Drupal\Core\Routing\RouteMatchInterface;
8 use Drupal\Core\TypedData\TypedDataInterface;
9 use Drupal\Core\Form\BaseFormIdInterface;
10 use Drupal\Core\Form\FormBase;
11 use Drupal\Core\Form\FormStateInterface;
12 use Drupal\language\ConfigurableLanguageManagerInterface;
13 use Symfony\Component\DependencyInjection\ContainerInterface;
14 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
15
16 /**
17  * Provides a base form for configuration translations.
18  */
19 abstract class ConfigTranslationFormBase extends FormBase implements BaseFormIdInterface {
20
21   /**
22    * The typed configuration manager.
23    *
24    * @var \Drupal\Core\Config\TypedConfigManagerInterface
25    */
26   protected $typedConfigManager;
27
28   /**
29    * The configuration mapper manager.
30    *
31    * @var \Drupal\config_translation\ConfigMapperManagerInterface
32    */
33   protected $configMapperManager;
34
35   /**
36    * The mapper for configuration translation.
37    *
38    * @var \Drupal\config_translation\ConfigMapperInterface
39    */
40   protected $mapper;
41
42   /**
43    * The language manager.
44    *
45    * @var \Drupal\language\ConfigurableLanguageManagerInterface
46    */
47   protected $languageManager;
48
49   /**
50    * The language of the configuration translation.
51    *
52    * @var \Drupal\Core\Language\LanguageInterface
53    */
54   protected $language;
55
56   /**
57    * The language of the configuration translation source.
58    *
59    * @var \Drupal\Core\Language\LanguageInterface
60    */
61   protected $sourceLanguage;
62
63   /**
64    * An array of base language configuration data keyed by configuration names.
65    *
66    * @var array
67    */
68   protected $baseConfigData = [];
69
70   /**
71    * Constructs a ConfigTranslationFormBase.
72    *
73    * @param \Drupal\Core\Config\TypedConfigManagerInterface $typed_config_manager
74    *   The typed configuration manager.
75    * @param \Drupal\config_translation\ConfigMapperManagerInterface $config_mapper_manager
76    *   The configuration mapper manager.
77    * @param \Drupal\language\ConfigurableLanguageManagerInterface $language_manager
78    *   The configurable language manager.
79    */
80   public function __construct(TypedConfigManagerInterface $typed_config_manager, ConfigMapperManagerInterface $config_mapper_manager, ConfigurableLanguageManagerInterface $language_manager) {
81     $this->typedConfigManager = $typed_config_manager;
82     $this->configMapperManager = $config_mapper_manager;
83     $this->languageManager = $language_manager;
84   }
85
86   /**
87    * {@inheritdoc}
88    */
89   public static function create(ContainerInterface $container) {
90     return new static(
91       $container->get('config.typed'),
92       $container->get('plugin.manager.config_translation.mapper'),
93       $container->get('language_manager')
94     );
95   }
96
97   /**
98    * {@inheritdoc}
99    */
100   public function getBaseFormId() {
101     return 'config_translation_form';
102   }
103
104   /**
105    * Implements \Drupal\Core\Form\FormInterface::buildForm().
106    *
107    * Builds configuration form with metadata and values from the source
108    * language.
109    *
110    * @param array $form
111    *   An associative array containing the structure of the form.
112    * @param \Drupal\Core\Form\FormStateInterface $form_state
113    *   The current state of the form.
114    * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
115    *   (optional) The route match.
116    * @param string $plugin_id
117    *   (optional) The plugin ID of the mapper.
118    * @param string $langcode
119    *   (optional) The language code of the language the form is adding or
120    *   editing.
121    *
122    * @return array
123    *   The form structure.
124    *
125    * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
126    *   Throws an exception if the language code provided as a query parameter in
127    *   the request does not match an active language.
128    */
129   public function buildForm(array $form, FormStateInterface $form_state, RouteMatchInterface $route_match = NULL, $plugin_id = NULL, $langcode = NULL) {
130     /** @var \Drupal\config_translation\ConfigMapperInterface $mapper */
131     $mapper = $this->configMapperManager->createInstance($plugin_id);
132     $mapper->populateFromRouteMatch($route_match);
133
134     $language = $this->languageManager->getLanguage($langcode);
135     if (!$language) {
136       throw new NotFoundHttpException();
137     }
138
139     $this->mapper = $mapper;
140     $this->language = $language;
141
142     // ConfigTranslationFormAccess will not grant access if this raises an
143     // exception, so we can call this without a try-catch block here.
144     $langcode = $this->mapper->getLangcode();
145
146     $this->sourceLanguage = $this->languageManager->getLanguage($langcode);
147
148     // Get base language configuration to display in the form before setting the
149     // language to use for the form. This avoids repetitively settings and
150     // resetting the language to get original values later.
151     $this->baseConfigData = $this->mapper->getConfigData();
152
153     // Set the translation target language on the configuration factory.
154     $original_language = $this->languageManager->getConfigOverrideLanguage();
155     $this->languageManager->setConfigOverrideLanguage($this->language);
156
157     // Add some information to the form state for easier form altering.
158     $form_state->set('config_translation_mapper', $this->mapper);
159     $form_state->set('config_translation_language', $this->language);
160     $form_state->set('config_translation_source_language', $this->sourceLanguage);
161
162     $form['#attached']['library'][] = 'config_translation/drupal.config_translation.admin';
163
164     // Even though this is a nested form, we do not set #tree to TRUE because
165     // the form value structure is generated by using #parents for each element.
166     // @see \Drupal\config_translation\FormElement\FormElementBase::getElements()
167     $form['config_names'] = ['#type' => 'container'];
168     foreach ($this->mapper->getConfigNames() as $name) {
169       $form['config_names'][$name] = ['#type' => 'container'];
170
171       $schema = $this->typedConfigManager->get($name);
172       $source_config = $this->baseConfigData[$name];
173       $translation_config = $this->configFactory()->get($name)->get();
174
175       if ($form_element = $this->createFormElement($schema)) {
176         $parents = ['config_names', $name];
177         $form['config_names'][$name] += $form_element->getTranslationBuild($this->sourceLanguage, $this->language, $source_config, $translation_config, $parents);
178       }
179     }
180
181     $form['actions']['#type'] = 'actions';
182     $form['actions']['submit'] = [
183       '#type' => 'submit',
184       '#value' => $this->t('Save translation'),
185       '#button_type' => 'primary',
186     ];
187
188     // Set the configuration language back.
189     $this->languageManager->setConfigOverrideLanguage($original_language);
190
191     return $form;
192   }
193
194   /**
195    * {@inheritdoc}
196    */
197   public function submitForm(array &$form, FormStateInterface $form_state) {
198     $form_values = $form_state->getValue(['translation', 'config_names']);
199
200     foreach ($form_values as $name => $value) {
201       $schema = $this->typedConfigManager->get($name);
202
203       // Set configuration values based on form submission and source values.
204       $base_config = $this->configFactory()->getEditable($name);
205       $config_translation = $this->languageManager->getLanguageConfigOverride($this->language->getId(), $name);
206
207       $element = $this->createFormElement($schema);
208       $element->setConfig($base_config, $config_translation, $value);
209
210       // If no overrides, delete language specific configuration file.
211       $saved_config = $config_translation->get();
212       if (empty($saved_config)) {
213         $config_translation->delete();
214       }
215       else {
216         $config_translation->save();
217       }
218     }
219
220     $form_state->setRedirect(
221       $this->mapper->getOverviewRoute(),
222       $this->mapper->getOverviewRouteParameters()
223     );
224   }
225
226   /**
227    * Creates a form element builder.
228    *
229    * @param \Drupal\Core\TypedData\TypedDataInterface $schema
230    *   Schema definition of configuration.
231    *
232    * @return \Drupal\config_translation\FormElement\ElementInterface|null
233    *   The element builder object if possible.
234    */
235   public static function createFormElement(TypedDataInterface $schema) {
236     $definition = $schema->getDataDefinition();
237     // Form element classes can be specified even for non-translatable elements
238     // such as the ListElement form element which is used for Mapping and
239     // Sequence schema elements.
240     if (isset($definition['form_element_class'])) {
241       if (!$definition->getLabel()) {
242         $definition->setLabel(t('n/a'));
243       }
244       $class = $definition['form_element_class'];
245       return $class::create($schema);
246     }
247   }
248
249 }