Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
| Total | |
0.00% |
0 / 1 |
|
25.00% |
1 / 4 |
CRAP | |
76.25% |
61 / 80 |
| LanguageNegotiationUrl | |
0.00% |
0 / 1 |
|
25.00% |
1 / 4 |
63.52 | |
76.25% |
61 / 80 |
| getLangcode | |
0.00% |
0 / 1 |
12.05 | |
92.86% |
26 / 28 |
|||
| processInbound | |
100.00% |
1 / 1 |
4 | |
100.00% |
8 / 8 |
|||
| processOutbound | |
0.00% |
0 / 1 |
33.44 | |
72.97% |
27 / 37 |
|||
| getLanguageSwitchLinks | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 7 |
|||
| <?php | |
| /** | |
| * @file | |
| * Contains \Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl. | |
| */ | |
| namespace Drupal\language\Plugin\LanguageNegotiation; | |
| use Drupal\Core\Language\LanguageInterface; | |
| use Drupal\Core\PathProcessor\InboundPathProcessorInterface; | |
| use Drupal\Core\PathProcessor\OutboundPathProcessorInterface; | |
| use Drupal\Core\Render\BubbleableMetadata; | |
| use Drupal\Core\Url; | |
| use Drupal\language\LanguageNegotiationMethodBase; | |
| use Drupal\language\LanguageSwitcherInterface; | |
| use Symfony\Component\HttpFoundation\Request; | |
| /** | |
| * Class for identifying language via URL prefix or domain. | |
| * | |
| * @LanguageNegotiation( | |
| * id = \Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl::METHOD_ID, | |
| * types = {\Drupal\Core\Language\LanguageInterface::TYPE_INTERFACE, | |
| * \Drupal\Core\Language\LanguageInterface::TYPE_CONTENT, | |
| * \Drupal\Core\Language\LanguageInterface::TYPE_URL}, | |
| * weight = -8, | |
| * name = @Translation("URL"), | |
| * description = @Translation("Language from the URL (Path prefix or domain)."), | |
| * config_route_name = "language.negotiation_url" | |
| * ) | |
| */ | |
| class LanguageNegotiationUrl extends LanguageNegotiationMethodBase implements InboundPathProcessorInterface, OutboundPathProcessorInterface, LanguageSwitcherInterface { | |
| /** | |
| * The language negotiation method id. | |
| */ | |
| const METHOD_ID = 'language-url'; | |
| /** | |
| * URL language negotiation: use the path prefix as URL language indicator. | |
| */ | |
| const CONFIG_PATH_PREFIX = 'path_prefix'; | |
| /** | |
| * URL language negotiation: use the domain as URL language indicator. | |
| */ | |
| const CONFIG_DOMAIN = 'domain'; | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function getLangcode(Request $request = NULL) { | |
| $langcode = NULL; | |
| if ($request && $this->languageManager) { | |
| $languages = $this->languageManager->getLanguages(); | |
| $config = $this->config->get('language.negotiation')->get('url'); | |
| switch ($config['source']) { | |
| case LanguageNegotiationUrl::CONFIG_PATH_PREFIX: | |
| $request_path = urldecode(trim($request->getPathInfo(), '/')); | |
| $path_args = explode('/', $request_path); | |
| $prefix = array_shift($path_args); | |
| // Search prefix within added languages. | |
| $negotiated_language = FALSE; | |
| foreach ($languages as $language) { | |
| if (isset($config['prefixes'][$language->getId()]) && $config['prefixes'][$language->getId()] == $prefix) { | |
| $negotiated_language = $language; | |
| break; | |
| } | |
| } | |
| if ($negotiated_language) { | |
| $langcode = $negotiated_language->getId(); | |
| } | |
| break; | |
| case LanguageNegotiationUrl::CONFIG_DOMAIN: | |
| // Get only the host, not the port. | |
| $http_host = $request->getHost(); | |
| foreach ($languages as $language) { | |
| // Skip the check if the language doesn't have a domain. | |
| if (!empty($config['domains'][$language->getId()])) { | |
| // Ensure that there is exactly one protocol in the URL when | |
| // checking the hostname. | |
| $host = 'http://' . str_replace(array('http://', 'https://'), '', $config['domains'][$language->getId()]); | |
| $host = parse_url($host, PHP_URL_HOST); | |
| if ($http_host == $host) { | |
| $langcode = $language->getId(); | |
| break; | |
| } | |
| } | |
| } | |
| break; | |
| } | |
| } | |
| return $langcode; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function processInbound($path, Request $request) { | |
| $config = $this->config->get('language.negotiation')->get('url'); | |
| $parts = explode('/', trim($path, '/')); | |
| $prefix = array_shift($parts); | |
| // Search prefix within added languages. | |
| foreach ($this->languageManager->getLanguages() as $language) { | |
| if (isset($config['prefixes'][$language->getId()]) && $config['prefixes'][$language->getId()] == $prefix) { | |
| // Rebuild $path with the language removed. | |
| $path = '/' . implode('/', $parts); | |
| break; | |
| } | |
| } | |
| return $path; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function processOutbound($path, &$options = array(), Request $request = NULL, BubbleableMetadata $bubbleable_metadata = NULL) { | |
| $url_scheme = 'http'; | |
| $port = 80; | |
| if ($request) { | |
| $url_scheme = $request->getScheme(); | |
| $port = $request->getPort(); | |
| } | |
| $languages = array_flip(array_keys($this->languageManager->getLanguages())); | |
| // Language can be passed as an option, or we go for current URL language. | |
| if (!isset($options['language'])) { | |
| $language_url = $this->languageManager->getCurrentLanguage(LanguageInterface::TYPE_URL); | |
| $options['language'] = $language_url; | |
| } | |
| // We allow only added languages here. | |
| elseif (!is_object($options['language']) || !isset($languages[$options['language']->getId()])) { | |
| return $path; | |
| } | |
| $config = $this->config->get('language.negotiation')->get('url'); | |
| if ($config['source'] == LanguageNegotiationUrl::CONFIG_PATH_PREFIX) { | |
| if (is_object($options['language']) && !empty($config['prefixes'][$options['language']->getId()])) { | |
| $options['prefix'] = $config['prefixes'][$options['language']->getId()] . '/'; | |
| if ($bubbleable_metadata) { | |
| $bubbleable_metadata->addCacheContexts(['languages:' . LanguageInterface::TYPE_URL]); | |
| } | |
| } | |
| } | |
| elseif ($config['source'] == LanguageNegotiationUrl::CONFIG_DOMAIN) { | |
| if (is_object($options['language']) && !empty($config['domains'][$options['language']->getId()])) { | |
| // Save the original base URL. If it contains a port, we need to | |
| // retain it below. | |
| if (!empty($options['base_url'])) { | |
| // The colon in the URL scheme messes up the port checking below. | |
| $normalized_base_url = str_replace(array('https://', 'http://'), '', $options['base_url']); | |
| } | |
| // Ask for an absolute URL with our modified base URL. | |
| $options['absolute'] = TRUE; | |
| $options['base_url'] = $url_scheme . '://' . $config['domains'][$options['language']->getId()]; | |
| // In case either the original base URL or the HTTP host contains a | |
| // port, retain it. | |
| if (isset($normalized_base_url) && strpos($normalized_base_url, ':') !== FALSE) { | |
| list(, $port) = explode(':', $normalized_base_url); | |
| $options['base_url'] .= ':' . $port; | |
| } | |
| elseif (($url_scheme == 'http' && $port != 80) || ($url_scheme == 'https' && $port != 443)) { | |
| $options['base_url'] .= ':' . $port; | |
| } | |
| if (isset($options['https'])) { | |
| if ($options['https'] === TRUE) { | |
| $options['base_url'] = str_replace('http://', 'https://', $options['base_url']); | |
| } | |
| elseif ($options['https'] === FALSE) { | |
| $options['base_url'] = str_replace('https://', 'http://', $options['base_url']); | |
| } | |
| } | |
| // Add Drupal's subfolder from the base_path if there is one. | |
| $options['base_url'] .= rtrim(base_path(), '/'); | |
| if ($bubbleable_metadata) { | |
| $bubbleable_metadata->addCacheContexts(['languages:' . LanguageInterface::TYPE_URL, 'url.site']); | |
| } | |
| } | |
| } | |
| return $path; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function getLanguageSwitchLinks(Request $request, $type, Url $url) { | |
| $links = array(); | |
| foreach ($this->languageManager->getNativeLanguages() as $language) { | |
| $links[$language->getId()] = array( | |
| // We need to clone the $url object to avoid using the same one for all | |
| // links. When the links are rendered, options are set on the $url | |
| // object, so if we use the same one, they would be set for all links. | |
| 'url' => clone $url, | |
| 'title' => $language->getName(), | |
| 'language' => $language, | |
| 'attributes' => array('class' => array('language-link')), | |
| ); | |
| } | |
| return $links; | |
| } | |
| } |