3 namespace Drupal\language\HttpKernel;
5 use Drupal\Component\Utility\Unicode;
6 use Drupal\Core\Config\ConfigFactoryInterface;
7 use Drupal\Core\PathProcessor\InboundPathProcessorInterface;
8 use Drupal\Core\PathProcessor\OutboundPathProcessorInterface;
9 use Drupal\Core\Render\BubbleableMetadata;
10 use Drupal\language\ConfigurableLanguageManagerInterface;
11 use Drupal\language\EventSubscriber\ConfigSubscriber;
12 use Drupal\language\LanguageNegotiatorInterface;
13 use Symfony\Component\HttpFoundation\Request;
14 use Drupal\Core\Session\AccountInterface;
17 * Processes the inbound path using path alias lookups.
19 class PathProcessorLanguage implements InboundPathProcessorInterface, OutboundPathProcessorInterface {
22 * A config factory for retrieving required config settings.
24 * @var \Drupal\Core\Config\ConfigFactoryInterface
29 * Language manager for retrieving the url language type.
31 * @var \Drupal\language\ConfigurableLanguageManagerInterface
33 protected $languageManager;
36 * The language negotiator.
38 * @var \Drupal\language\LanguageNegotiatorInterface
40 protected $negotiator;
43 * Local cache for language path processors.
47 protected $processors;
50 * Flag indicating whether the site is multilingual.
54 protected $multilingual;
57 * The language configuration event subscriber.
59 * @var \Drupal\language\EventSubscriber\ConfigSubscriber
61 protected $configSubscriber;
64 * Constructs a PathProcessorLanguage object.
66 * @param \Drupal\Core\Config\ConfigFactoryInterface $config
67 * A config factory object for retrieving configuration settings.
68 * @param \Drupal\language\ConfigurableLanguageManagerInterface $language_manager
69 * The configurable language manager.
70 * @param \Drupal\language\LanguageNegotiatorInterface $negotiator
71 * The language negotiator.
72 * @param \Drupal\Core\Session\AccountInterface $current_user
73 * The current active user.
74 * @param \Drupal\language\EventSubscriber\ConfigSubscriber $config_subscriber
75 * The language configuration event subscriber.
77 public function __construct(ConfigFactoryInterface $config, ConfigurableLanguageManagerInterface $language_manager, LanguageNegotiatorInterface $negotiator, AccountInterface $current_user, ConfigSubscriber $config_subscriber) {
78 $this->config = $config;
79 $this->languageManager = $language_manager;
80 $this->negotiator = $negotiator;
81 $this->negotiator->setCurrentUser($current_user);
82 $this->configSubscriber = $config_subscriber;
88 public function processInbound($path, Request $request) {
91 if (!isset($this->processors[$scope])) {
92 $this->initProcessors($scope);
94 foreach ($this->processors[$scope] as $instance) {
95 $path = $instance->processInbound($path, $request);
104 public function processOutbound($path, &$options = [], Request $request = NULL, BubbleableMetadata $bubbleable_metadata = NULL) {
105 if (!isset($this->multilingual)) {
106 $this->multilingual = $this->languageManager->isMultilingual();
108 if ($this->multilingual) {
109 $this->negotiator->reset();
111 if (!isset($this->processors[$scope])) {
112 $this->initProcessors($scope);
114 foreach ($this->processors[$scope] as $instance) {
115 $path = $instance->processOutbound($path, $options, $request, $bubbleable_metadata);
117 // No language dependent path allowed in this mode.
118 if (empty($this->processors[$scope])) {
119 unset($options['language']);
126 * Initializes the local cache for language path processors.
128 * @param string $scope
129 * The scope of the processors: "inbound" or "outbound".
131 protected function initProcessors($scope) {
132 $interface = '\Drupal\Core\PathProcessor\\' . Unicode::ucfirst($scope) . 'PathProcessorInterface';
133 $this->processors[$scope] = [];
135 foreach ($this->languageManager->getLanguageTypes() as $type) {
136 foreach ($this->negotiator->getNegotiationMethods($type) as $method_id => $method) {
137 if (!isset($this->processors[$scope][$method_id])) {
138 $reflector = new \ReflectionClass($method['class']);
139 if ($reflector->implementsInterface($interface)) {
140 $this->processors[$scope][$method_id] = $this->negotiator->getNegotiationMethodInstance($method_id);
141 $weights[$method_id] = $method['weight'];
147 // Sort the processors list, so that their functions are called in the
148 // order specified by the weight of the methods.
149 uksort($this->processors[$scope], function ($method_id_a, $method_id_b) use ($weights) {
150 $a_weight = $weights[$method_id_a];
151 $b_weight = $weights[$method_id_b];
153 if ($a_weight == $b_weight) {
157 return ($a_weight < $b_weight) ? -1 : 1;
162 * Initializes the injected event subscriber with the language path processor.
164 * The language path processor service is registered only on multilingual
165 * site configuration, thus we inject it in the event subscriber only when
168 public function initConfigSubscriber() {
169 $this->configSubscriber->setPathProcessorLanguage($this);
173 * Resets the collected processors instances.
175 public function reset() {
176 $this->processors = [];