View source
<?php
namespace Drupal\language\Plugin\LanguageNegotiation;
use Drupal\Component\Utility\UrlHelper;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\PathProcessor\OutboundPathProcessorInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Render\BubbleableMetadata;
use Drupal\Core\Url;
use Drupal\language\LanguageNegotiationMethodBase;
use Drupal\language\LanguageSwitcherInterface;
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Route;
class LanguageNegotiationContentEntity extends LanguageNegotiationMethodBase implements OutboundPathProcessorInterface, LanguageSwitcherInterface, ContainerFactoryPluginInterface {
const METHOD_ID = 'language-content-entity';
const QUERY_PARAMETER = 'language_content_entity';
protected $contentEntityPaths;
protected $hasLowerLanguageNegotiationWeightResult;
protected $paths;
protected $entityManager;
public function __construct(EntityManagerInterface $entity_manager) {
$this->entityManager = $entity_manager;
$this->paths = new \SplObjectStorage();
}
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static($container
->get('entity.manager'));
}
public function getLangcode(Request $request = NULL) {
$langcode = $request
->get(static::QUERY_PARAMETER);
$language_enabled = array_key_exists($langcode, $this->languageManager
->getLanguages());
return $language_enabled ? $langcode : NULL;
}
public function processOutbound($path, &$options = [], Request $request = NULL, BubbleableMetadata $bubbleable_metadata = NULL) {
if (!($request && !empty($options['route']) && $this
->hasLowerLanguageNegotiationWeight() && $this
->meetsContentEntityRoutesCondition($options['route'], $request))) {
return $path;
}
if (isset($options['language']) || ($langcode = $this
->getLangcode($request))) {
if (isset($options['language'])) {
$langcode = $options['language']
->getId();
unset($options['language']);
}
if (isset($options['query']) && is_string($options['query'])) {
$query = [];
parse_str($options['query'], $query);
$options['query'] = $query;
}
else {
$options['query'] = [];
}
if (!isset($options['query'][static::QUERY_PARAMETER])) {
$query_addon = [
static::QUERY_PARAMETER => $langcode,
];
$options['query'] += $query_addon;
$path .= (strpos($path, '?') !== FALSE ? '&' : '?') . UrlHelper::buildQuery($query_addon);
}
if ($bubbleable_metadata) {
$bubbleable_metadata
->addCacheContexts([
'url.query_args:' . static::QUERY_PARAMETER,
]);
}
}
return $path;
}
public function getLanguageSwitchLinks(Request $request, $type, Url $url) {
$links = [];
$query = [];
parse_str($request
->getQueryString(), $query);
foreach ($this->languageManager
->getNativeLanguages() as $language) {
$langcode = $language
->getId();
$query[static::QUERY_PARAMETER] = $langcode;
$links[$langcode] = [
'url' => $url,
'title' => $language
->getName(),
'attributes' => [
'class' => [
'language-link',
],
],
'query' => $query,
];
}
return $links;
}
protected function hasLowerLanguageNegotiationWeight() {
if (!isset($this->hasLowerLanguageNegotiationWeightResult)) {
$content_method_weights = $this->config
->get('language.types')
->get('negotiation.language_content.enabled') ?: [];
if (isset($content_method_weights[LanguageNegotiationUrl::METHOD_ID]) && $content_method_weights[static::METHOD_ID] > $content_method_weights[LanguageNegotiationUrl::METHOD_ID]) {
$this->hasLowerLanguageNegotiationWeightResult = FALSE;
}
else {
$check_interface_method = FALSE;
if (isset($content_method_weights[LanguageNegotiationUI::METHOD_ID])) {
$interface_method_weights = $this->config
->get('language.types')
->get('negotiation.language_interface.enabled') ?: [];
$check_interface_method = isset($interface_method_weights[LanguageNegotiationUrl::METHOD_ID]);
}
if ($check_interface_method) {
$max_weight = $content_method_weights[LanguageNegotiationUI::METHOD_ID];
$max_weight = isset($content_method_weights[LanguageNegotiationUrl::METHOD_ID]) ? max($max_weight, $content_method_weights[LanguageNegotiationUrl::METHOD_ID]) : $max_weight;
}
else {
$max_weight = isset($content_method_weights[LanguageNegotiationUrl::METHOD_ID]) ? $content_method_weights[LanguageNegotiationUrl::METHOD_ID] : PHP_INT_MAX;
}
$this->hasLowerLanguageNegotiationWeightResult = $content_method_weights[static::METHOD_ID] < $max_weight;
}
}
return $this->hasLowerLanguageNegotiationWeightResult;
}
protected function meetsContentEntityRoutesCondition(Route $outbound_route, Request $request) {
$outbound_path_pattern = $outbound_route
->getPath();
$storage = isset($this->paths[$request]) ? $this->paths[$request] : [];
if (!isset($storage[$outbound_path_pattern])) {
$storage[$outbound_path_pattern] = FALSE;
if ($content_entity_type_id_for_current_route = $this
->getContentEntityTypeIdForCurrentRequest($request)) {
if (!empty($this
->getContentEntityPaths()[$outbound_path_pattern]) && $content_entity_type_id_for_current_route == $this
->getContentEntityPaths()[$outbound_path_pattern]) {
$storage[$outbound_path_pattern] = TRUE;
}
}
$this->paths[$request] = $storage;
}
return $storage[$outbound_path_pattern];
}
protected function getContentEntityTypeIdForCurrentRequest(Request $request) {
$content_entity_type_id_for_current_route = '';
if ($current_route = $request->attributes
->get(RouteObjectInterface::ROUTE_OBJECT)) {
$current_route_path = $current_route
->getPath();
$content_entity_type_id_for_current_route = isset($this
->getContentEntityPaths()[$current_route_path]) ? $this
->getContentEntityPaths()[$current_route_path] : '';
}
return $content_entity_type_id_for_current_route;
}
protected function getContentEntityPaths() {
if (!isset($this->contentEntityPaths)) {
$this->contentEntityPaths = [];
$entity_types = $this->entityManager
->getDefinitions();
foreach ($entity_types as $entity_type_id => $entity_type) {
if ($entity_type
->isSubclassOf(ContentEntityInterface::class)) {
$entity_paths = array_fill_keys($entity_type
->getLinkTemplates(), $entity_type_id);
$this->contentEntityPaths = array_merge($this->contentEntityPaths, $entity_paths);
}
}
}
return $this->contentEntityPaths;
}
}