PageRenderTime 39ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/web/core/modules/language/src/Form/NegotiationUrlForm.php

https://gitlab.com/mohamed_hussein/prodt
PHP | 220 lines | 145 code | 23 blank | 52 comment | 15 complexity | 1020a70556e3afd24aec0c260d4a0e53 MD5 | raw file
  1. <?php
  2. namespace Drupal\language\Form;
  3. use Drupal\Core\Form\ConfigFormBase;
  4. use Drupal\Core\Form\FormStateInterface;
  5. use Drupal\Core\Language\LanguageInterface;
  6. use Drupal\Core\Language\LanguageManagerInterface;
  7. use Drupal\Core\Config\ConfigFactoryInterface;
  8. use Drupal\Core\Url;
  9. use Symfony\Component\DependencyInjection\ContainerInterface;
  10. use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl;
  11. /**
  12. * Configure the URL language negotiation method for this site.
  13. *
  14. * @internal
  15. */
  16. class NegotiationUrlForm extends ConfigFormBase {
  17. /**
  18. * The language manager.
  19. *
  20. * @var \Drupal\Core\Language\LanguageManagerInterface
  21. */
  22. protected $languageManager;
  23. /**
  24. * Constructs a new NegotiationUrlForm object.
  25. *
  26. * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
  27. * The factory for configuration objects.
  28. * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
  29. * The language manager.
  30. */
  31. public function __construct(ConfigFactoryInterface $config_factory, LanguageManagerInterface $language_manager) {
  32. parent::__construct($config_factory);
  33. $this->languageManager = $language_manager;
  34. }
  35. /**
  36. * {@inheritdoc}
  37. */
  38. public static function create(ContainerInterface $container) {
  39. return new static(
  40. $container->get('config.factory'),
  41. $container->get('language_manager')
  42. );
  43. }
  44. /**
  45. * {@inheritdoc}
  46. */
  47. public function getFormId() {
  48. return 'language_negotiation_configure_url_form';
  49. }
  50. /**
  51. * {@inheritdoc}
  52. */
  53. protected function getEditableConfigNames() {
  54. return ['language.negotiation'];
  55. }
  56. /**
  57. * {@inheritdoc}
  58. */
  59. public function buildForm(array $form, FormStateInterface $form_state) {
  60. global $base_url;
  61. $config = $this->config('language.negotiation');
  62. $form['language_negotiation_url_part'] = [
  63. '#title' => $this->t('Part of the URL that determines language'),
  64. '#type' => 'radios',
  65. '#options' => [
  66. LanguageNegotiationUrl::CONFIG_PATH_PREFIX => $this->t('Path prefix'),
  67. LanguageNegotiationUrl::CONFIG_DOMAIN => $this->t('Domain'),
  68. ],
  69. '#default_value' => $config->get('url.source'),
  70. ];
  71. $form['prefix'] = [
  72. '#type' => 'details',
  73. '#tree' => TRUE,
  74. '#title' => $this->t('Path prefix configuration'),
  75. '#open' => TRUE,
  76. '#description' => $this->t('Language codes or other custom text to use as a path prefix for URL language detection. For the selected fallback language, this value may be left blank. <strong>Modifying this value may break existing URLs. Use with caution in a production environment.</strong> Example: Specifying "deutsch" as the path prefix code for German results in URLs like "example.com/deutsch/contact".'),
  77. '#states' => [
  78. 'visible' => [
  79. ':input[name="language_negotiation_url_part"]' => [
  80. 'value' => (string) LanguageNegotiationUrl::CONFIG_PATH_PREFIX,
  81. ],
  82. ],
  83. ],
  84. ];
  85. $form['domain'] = [
  86. '#type' => 'details',
  87. '#tree' => TRUE,
  88. '#title' => $this->t('Domain configuration'),
  89. '#open' => TRUE,
  90. '#description' => $this->t('The domain names to use for these languages. <strong>Modifying this value may break existing URLs. Use with caution in a production environment.</strong> Example: Specifying "de.example.com" as language domain for German will result in a URL like "http://de.example.com/contact".'),
  91. '#states' => [
  92. 'visible' => [
  93. ':input[name="language_negotiation_url_part"]' => [
  94. 'value' => (string) LanguageNegotiationUrl::CONFIG_DOMAIN,
  95. ],
  96. ],
  97. ],
  98. ];
  99. $languages = $this->languageManager->getLanguages();
  100. $prefixes = $config->get('url.prefixes');
  101. $domains = $config->get('url.domains');
  102. foreach ($languages as $langcode => $language) {
  103. $t_args = ['%language' => $language->getName(), '%langcode' => $language->getId()];
  104. $form['prefix'][$langcode] = [
  105. '#type' => 'textfield',
  106. '#title' => $language->isDefault() ? $this->t('%language (%langcode) path prefix (Default language)', $t_args) : $this->t('%language (%langcode) path prefix', $t_args),
  107. '#maxlength' => 64,
  108. '#default_value' => $prefixes[$langcode] ?? '',
  109. '#field_prefix' => $base_url . '/',
  110. ];
  111. $form['domain'][$langcode] = [
  112. '#type' => 'textfield',
  113. '#title' => $this->t('%language (%langcode) domain', ['%language' => $language->getName(), '%langcode' => $language->getId()]),
  114. '#maxlength' => 128,
  115. '#default_value' => $domains[$langcode] ?? '',
  116. ];
  117. }
  118. $form_state->setRedirect('language.negotiation');
  119. return parent::buildForm($form, $form_state);
  120. }
  121. /**
  122. * {@inheritdoc}
  123. */
  124. public function validateForm(array &$form, FormStateInterface $form_state) {
  125. $languages = $this->languageManager->getLanguages();
  126. // Count repeated values for uniqueness check.
  127. $count = array_count_values($form_state->getValue('prefix'));
  128. $default_langcode = $this->config('language.negotiation')->get('selected_langcode');
  129. if ($default_langcode == LanguageInterface::LANGCODE_SITE_DEFAULT) {
  130. $default_langcode = $this->languageManager->getDefaultLanguage()->getId();
  131. }
  132. foreach ($languages as $langcode => $language) {
  133. $value = $form_state->getValue(['prefix', $langcode]);
  134. if ($value === '') {
  135. if (!($default_langcode == $langcode) && $form_state->getValue('language_negotiation_url_part') == LanguageNegotiationUrl::CONFIG_PATH_PREFIX) {
  136. // Throw a form error if the prefix is blank for a non-default language,
  137. // although it is required for selected negotiation type.
  138. $form_state->setErrorByName("prefix][$langcode", $this->t('The prefix may only be left blank for the <a href=":url">selected detection fallback language.</a>', [
  139. ':url' => Url::fromRoute('language.negotiation_selected')->toString(),
  140. ]));
  141. }
  142. }
  143. elseif (strpos($value, '/') !== FALSE) {
  144. // Throw a form error if the string contains a slash,
  145. // which would not work.
  146. $form_state->setErrorByName("prefix][$langcode", $this->t('The prefix may not contain a slash.'));
  147. }
  148. elseif (isset($count[$value]) && $count[$value] > 1) {
  149. // Throw a form error if there are two languages with the same
  150. // domain/prefix.
  151. $form_state->setErrorByName("prefix][$langcode", $this->t('The prefix for %language, %value, is not unique.', ['%language' => $language->getName(), '%value' => $value]));
  152. }
  153. }
  154. // Count repeated values for uniqueness check.
  155. $count = array_count_values($form_state->getValue('domain'));
  156. foreach ($languages as $langcode => $language) {
  157. $value = $form_state->getValue(['domain', $langcode]);
  158. if ($value === '') {
  159. if ($form_state->getValue('language_negotiation_url_part') == LanguageNegotiationUrl::CONFIG_DOMAIN) {
  160. // Throw a form error if the domain is blank for a non-default language,
  161. // although it is required for selected negotiation type.
  162. $form_state->setErrorByName("domain][$langcode", $this->t('The domain may not be left blank for %language.', ['%language' => $language->getName()]));
  163. }
  164. }
  165. elseif (isset($count[$value]) && $count[$value] > 1) {
  166. // Throw a form error if there are two languages with the same
  167. // domain/domain.
  168. $form_state->setErrorByName("domain][$langcode", $this->t('The domain for %language, %value, is not unique.', ['%language' => $language->getName(), '%value' => $value]));
  169. }
  170. }
  171. // Domain names should not contain protocol and/or ports.
  172. foreach ($languages as $langcode => $language) {
  173. $value = $form_state->getValue(['domain', $langcode]);
  174. if (!empty($value)) {
  175. // Ensure we have exactly one protocol when checking the hostname.
  176. $host = 'http://' . str_replace(['http://', 'https://'], '', $value);
  177. if (parse_url($host, PHP_URL_HOST) != $value) {
  178. $form_state->setErrorByName("domain][$langcode", $this->t('The domain for %language may only contain the domain name, not a trailing slash, protocol and/or port.', ['%language' => $language->getName()]));
  179. }
  180. }
  181. }
  182. parent::validateForm($form, $form_state);
  183. }
  184. /**
  185. * {@inheritdoc}
  186. */
  187. public function submitForm(array &$form, FormStateInterface $form_state) {
  188. // Save selected format (prefix or domain).
  189. $this->config('language.negotiation')
  190. ->set('url.source', $form_state->getValue('language_negotiation_url_part'))
  191. // Save new domain and prefix values.
  192. ->set('url.prefixes', $form_state->getValue('prefix'))
  193. ->set('url.domains', $form_state->getValue('domain'))
  194. ->save();
  195. parent::submitForm($form, $form_state);
  196. }
  197. }