Security update for Core, with self-updated composer
[yaffs-website] / web / core / modules / language / src / Form / NegotiationBrowserForm.php
1 <?php
2
3 namespace Drupal\language\Form;
4
5 use Drupal\Core\Config\ConfigFactoryInterface;
6 use Drupal\Core\Form\ConfigFormBase;
7 use Drupal\Core\Form\FormStateInterface;
8 use Drupal\Core\Url;
9 use Drupal\language\ConfigurableLanguageManagerInterface;
10 use Symfony\Component\DependencyInjection\ContainerInterface;
11
12 /**
13  * Configure the browser language negotiation method for this site.
14  */
15 class NegotiationBrowserForm extends ConfigFormBase {
16
17   /**
18    * The configurable language manager.
19    *
20    * @var \Drupal\language\ConfigurableLanguageManagerInterface
21    */
22   protected $languageManager;
23
24   /**
25    * {@inheritdoc}
26    */
27   public function __construct(ConfigFactoryInterface $config_factory, ConfigurableLanguageManagerInterface $language_manager) {
28     parent::__construct($config_factory);
29     $this->languageManager = $language_manager;
30   }
31
32   /**
33    * {@inheritdoc}
34    */
35   public static function create(ContainerInterface $container) {
36     return new static(
37       $container->get('config.factory'),
38       $container->get('language_manager')
39     );
40   }
41
42   /**
43    * {@inheritdoc}
44    */
45   public function getFormId() {
46     return 'language_negotiation_configure_browser_form';
47   }
48
49   /**
50    * {@inheritdoc}
51    */
52   protected function getEditableConfigNames() {
53     return ['language.mappings'];
54   }
55
56   /**
57    * {@inheritdoc}
58    */
59   public function buildForm(array $form, FormStateInterface $form_state) {
60     $form = [];
61
62     // Initialize a language list to the ones available, including English.
63     $languages = $this->languageManager->getLanguages();
64
65     $existing_languages = [];
66     foreach ($languages as $langcode => $language) {
67       $existing_languages[$langcode] = $language->getName();
68     }
69
70     // If we have no languages available, present the list of predefined languages
71     // only. If we do have already added languages, set up two option groups with
72     // the list of existing and then predefined languages.
73     if (empty($existing_languages)) {
74       $language_options = $this->languageManager->getStandardLanguageListWithoutConfigured();
75     }
76     else {
77       $language_options = [
78         (string) $this->t('Existing languages') => $existing_languages,
79         (string) $this->t('Languages not yet added') => $this->languageManager->getStandardLanguageListWithoutConfigured(),
80       ];
81     }
82
83     $form['mappings'] = [
84       '#type' => 'table',
85       '#header' => [
86         $this->t('Browser language code'),
87         $this->t('Site language'),
88         $this->t('Operations'),
89       ],
90       '#attributes' => ['id' => 'language-negotiation-browser'],
91       '#empty' => $this->t('No browser language mappings available.'),
92     ];
93
94     $mappings = $this->language_get_browser_drupal_langcode_mappings();
95     foreach ($mappings as $browser_langcode => $drupal_langcode) {
96       $form['mappings'][$browser_langcode] = [
97         'browser_langcode' => [
98           '#title' => $this->t('Browser language code'),
99           '#title_display' => 'invisible',
100           '#type' => 'textfield',
101           '#default_value' => $browser_langcode,
102           '#size' => 20,
103           '#required' => TRUE,
104         ],
105         'drupal_langcode' => [
106           '#title' => $this->t('Site language'),
107           '#title_display' => 'invisible',
108           '#type' => 'select',
109           '#options' => $language_options,
110           '#default_value' => $drupal_langcode,
111           '#required' => TRUE,
112         ],
113       ];
114       // Operations column.
115       $form['mappings'][$browser_langcode]['operations'] = [
116         '#type' => 'operations',
117         '#links' => [],
118       ];
119       $form['mappings'][$browser_langcode]['operations']['#links']['delete'] = [
120         'title' => $this->t('Delete'),
121         'url' => Url::fromRoute('language.negotiation_browser_delete', ['browser_langcode' => $browser_langcode]),
122       ];
123     }
124
125     // Add empty row.
126     $form['new_mapping'] = [
127       '#type' => 'details',
128       '#title' => $this->t('Add a new mapping'),
129       '#tree' => TRUE,
130     ];
131     $form['new_mapping']['browser_langcode'] = [
132       '#type' => 'textfield',
133       '#title' => $this->t('Browser language code'),
134       '#description' => $this->t('Use language codes as <a href=":w3ctags">defined by the W3C</a> for interoperability. <em>Examples: "en", "en-gb" and "zh-hant".</em>', [':w3ctags' => 'http://www.w3.org/International/articles/language-tags/']),
135       '#size' => 20,
136     ];
137     $form['new_mapping']['drupal_langcode'] = [
138       '#type' => 'select',
139       '#title' => $this->t('Site language'),
140       '#options' => $language_options,
141     ];
142
143     return parent::buildForm($form, $form_state);
144   }
145
146   /**
147    * {@inheritdoc}
148    */
149   public function validateForm(array &$form, FormStateInterface $form_state) {
150     // Array to check if all browser language codes are unique.
151     $unique_values = [];
152
153     // Check all mappings.
154     if ($form_state->hasValue('mappings')) {
155       $mappings = $form_state->getValue('mappings');
156       foreach ($mappings as $key => $data) {
157         // Make sure browser_langcode is unique.
158         if (array_key_exists($data['browser_langcode'], $unique_values)) {
159           $form_state->setErrorByName('mappings][new_mapping][browser_langcode', $this->t('Browser language codes must be unique.'));
160         }
161         elseif (preg_match('/[^a-z\-]/', $data['browser_langcode'])) {
162           $form_state->setErrorByName('mappings][new_mapping][browser_langcode', $this->t('Browser language codes can only contain lowercase letters and a hyphen(-).'));
163         }
164         $unique_values[$data['browser_langcode']] = $data['drupal_langcode'];
165       }
166     }
167
168     // Check new mapping.
169     $data = $form_state->getValue('new_mapping');
170     if (!empty($data['browser_langcode'])) {
171       // Make sure browser_langcode is unique.
172       if (array_key_exists($data['browser_langcode'], $unique_values)) {
173         $form_state->setErrorByName('mappings][' . $key . '][browser_langcode', $this->t('Browser language codes must be unique.'));
174       }
175       elseif (preg_match('/[^a-z\-]/', $data['browser_langcode'])) {
176         $form_state->setErrorByName('mappings][' . $key . '][browser_langcode', $this->t('Browser language codes can only contain lowercase letters and a hyphen(-).'));
177       }
178       $unique_values[$data['browser_langcode']] = $data['drupal_langcode'];
179     }
180
181     $form_state->set('mappings', $unique_values);
182   }
183
184   /**
185    * {@inheritdoc}
186    */
187   public function submitForm(array &$form, FormStateInterface $form_state) {
188     $mappings = $form_state->get('mappings');
189     if (!empty($mappings)) {
190       $config = $this->config('language.mappings');
191       $config->setData(['map' => $mappings]);
192       $config->save();
193     }
194
195     parent::submitForm($form, $form_state);
196   }
197
198   /**
199    * Retrieves the browser's langcode mapping configuration array.
200    *
201    * @return array
202    *   The browser's langcode mapping configuration array.
203    */
204   protected function language_get_browser_drupal_langcode_mappings() {
205     $config = $this->config('language.mappings');
206     if ($config->isNew()) {
207       return [];
208     }
209     return $config->get('map');
210   }
211
212 }