Chris@0
|
1 <?php
|
Chris@0
|
2
|
Chris@0
|
3 namespace Drupal\language\HttpKernel;
|
Chris@0
|
4
|
Chris@0
|
5 use Drupal\Component\Utility\Unicode;
|
Chris@0
|
6 use Drupal\Core\Config\ConfigFactoryInterface;
|
Chris@0
|
7 use Drupal\Core\PathProcessor\InboundPathProcessorInterface;
|
Chris@0
|
8 use Drupal\Core\PathProcessor\OutboundPathProcessorInterface;
|
Chris@0
|
9 use Drupal\Core\Render\BubbleableMetadata;
|
Chris@0
|
10 use Drupal\language\ConfigurableLanguageManagerInterface;
|
Chris@0
|
11 use Drupal\language\EventSubscriber\ConfigSubscriber;
|
Chris@0
|
12 use Drupal\language\LanguageNegotiatorInterface;
|
Chris@0
|
13 use Symfony\Component\HttpFoundation\Request;
|
Chris@0
|
14 use Drupal\Core\Session\AccountInterface;
|
Chris@0
|
15
|
Chris@0
|
16 /**
|
Chris@0
|
17 * Processes the inbound path using path alias lookups.
|
Chris@0
|
18 */
|
Chris@0
|
19 class PathProcessorLanguage implements InboundPathProcessorInterface, OutboundPathProcessorInterface {
|
Chris@0
|
20
|
Chris@0
|
21 /**
|
Chris@0
|
22 * A config factory for retrieving required config settings.
|
Chris@0
|
23 *
|
Chris@0
|
24 * @var \Drupal\Core\Config\ConfigFactoryInterface
|
Chris@0
|
25 */
|
Chris@0
|
26 protected $config;
|
Chris@0
|
27
|
Chris@0
|
28 /**
|
Chris@0
|
29 * Language manager for retrieving the url language type.
|
Chris@0
|
30 *
|
Chris@0
|
31 * @var \Drupal\language\ConfigurableLanguageManagerInterface
|
Chris@0
|
32 */
|
Chris@0
|
33 protected $languageManager;
|
Chris@0
|
34
|
Chris@0
|
35 /**
|
Chris@0
|
36 * The language negotiator.
|
Chris@0
|
37 *
|
Chris@0
|
38 * @var \Drupal\language\LanguageNegotiatorInterface
|
Chris@0
|
39 */
|
Chris@0
|
40 protected $negotiator;
|
Chris@0
|
41
|
Chris@0
|
42 /**
|
Chris@0
|
43 * Local cache for language path processors.
|
Chris@0
|
44 *
|
Chris@0
|
45 * @var array
|
Chris@0
|
46 */
|
Chris@0
|
47 protected $processors;
|
Chris@0
|
48
|
Chris@0
|
49 /**
|
Chris@0
|
50 * Flag indicating whether the site is multilingual.
|
Chris@0
|
51 *
|
Chris@0
|
52 * @var bool
|
Chris@0
|
53 */
|
Chris@0
|
54 protected $multilingual;
|
Chris@0
|
55
|
Chris@0
|
56 /**
|
Chris@0
|
57 * The language configuration event subscriber.
|
Chris@0
|
58 *
|
Chris@0
|
59 * @var \Drupal\language\EventSubscriber\ConfigSubscriber
|
Chris@0
|
60 */
|
Chris@0
|
61 protected $configSubscriber;
|
Chris@0
|
62
|
Chris@0
|
63
|
Chris@0
|
64 /**
|
Chris@0
|
65 * Constructs a PathProcessorLanguage object.
|
Chris@0
|
66 *
|
Chris@0
|
67 * @param \Drupal\Core\Config\ConfigFactoryInterface $config
|
Chris@0
|
68 * A config factory object for retrieving configuration settings.
|
Chris@0
|
69 * @param \Drupal\language\ConfigurableLanguageManagerInterface $language_manager
|
Chris@0
|
70 * The configurable language manager.
|
Chris@0
|
71 * @param \Drupal\language\LanguageNegotiatorInterface $negotiator
|
Chris@0
|
72 * The language negotiator.
|
Chris@0
|
73 * @param \Drupal\Core\Session\AccountInterface $current_user
|
Chris@0
|
74 * The current active user.
|
Chris@0
|
75 * @param \Drupal\language\EventSubscriber\ConfigSubscriber $config_subscriber
|
Chris@0
|
76 * The language configuration event subscriber.
|
Chris@0
|
77 */
|
Chris@0
|
78 public function __construct(ConfigFactoryInterface $config, ConfigurableLanguageManagerInterface $language_manager, LanguageNegotiatorInterface $negotiator, AccountInterface $current_user, ConfigSubscriber $config_subscriber) {
|
Chris@0
|
79 $this->config = $config;
|
Chris@0
|
80 $this->languageManager = $language_manager;
|
Chris@0
|
81 $this->negotiator = $negotiator;
|
Chris@0
|
82 $this->negotiator->setCurrentUser($current_user);
|
Chris@0
|
83 $this->configSubscriber = $config_subscriber;
|
Chris@0
|
84 }
|
Chris@0
|
85
|
Chris@0
|
86 /**
|
Chris@0
|
87 * {@inheritdoc}
|
Chris@0
|
88 */
|
Chris@0
|
89 public function processInbound($path, Request $request) {
|
Chris@0
|
90 if (!empty($path)) {
|
Chris@0
|
91 $scope = 'inbound';
|
Chris@0
|
92 if (!isset($this->processors[$scope])) {
|
Chris@0
|
93 $this->initProcessors($scope);
|
Chris@0
|
94 }
|
Chris@0
|
95 foreach ($this->processors[$scope] as $instance) {
|
Chris@0
|
96 $path = $instance->processInbound($path, $request);
|
Chris@0
|
97 }
|
Chris@0
|
98 }
|
Chris@0
|
99 return $path;
|
Chris@0
|
100 }
|
Chris@0
|
101
|
Chris@0
|
102 /**
|
Chris@0
|
103 * {@inheritdoc}
|
Chris@0
|
104 */
|
Chris@0
|
105 public function processOutbound($path, &$options = [], Request $request = NULL, BubbleableMetadata $bubbleable_metadata = NULL) {
|
Chris@0
|
106 if (!isset($this->multilingual)) {
|
Chris@0
|
107 $this->multilingual = $this->languageManager->isMultilingual();
|
Chris@0
|
108 }
|
Chris@0
|
109 if ($this->multilingual) {
|
Chris@0
|
110 $this->negotiator->reset();
|
Chris@0
|
111 $scope = 'outbound';
|
Chris@0
|
112 if (!isset($this->processors[$scope])) {
|
Chris@0
|
113 $this->initProcessors($scope);
|
Chris@0
|
114 }
|
Chris@0
|
115 foreach ($this->processors[$scope] as $instance) {
|
Chris@0
|
116 $path = $instance->processOutbound($path, $options, $request, $bubbleable_metadata);
|
Chris@0
|
117 }
|
Chris@0
|
118 // No language dependent path allowed in this mode.
|
Chris@0
|
119 if (empty($this->processors[$scope])) {
|
Chris@0
|
120 unset($options['language']);
|
Chris@0
|
121 }
|
Chris@0
|
122 }
|
Chris@0
|
123 return $path;
|
Chris@0
|
124 }
|
Chris@0
|
125
|
Chris@0
|
126 /**
|
Chris@0
|
127 * Initializes the local cache for language path processors.
|
Chris@0
|
128 *
|
Chris@0
|
129 * @param string $scope
|
Chris@0
|
130 * The scope of the processors: "inbound" or "outbound".
|
Chris@0
|
131 */
|
Chris@0
|
132 protected function initProcessors($scope) {
|
Chris@0
|
133 $interface = '\Drupal\Core\PathProcessor\\' . Unicode::ucfirst($scope) . 'PathProcessorInterface';
|
Chris@0
|
134 $this->processors[$scope] = [];
|
Chris@0
|
135 $weights = [];
|
Chris@0
|
136 foreach ($this->languageManager->getLanguageTypes() as $type) {
|
Chris@0
|
137 foreach ($this->negotiator->getNegotiationMethods($type) as $method_id => $method) {
|
Chris@0
|
138 if (!isset($this->processors[$scope][$method_id])) {
|
Chris@0
|
139 $reflector = new \ReflectionClass($method['class']);
|
Chris@0
|
140 if ($reflector->implementsInterface($interface)) {
|
Chris@0
|
141 $this->processors[$scope][$method_id] = $this->negotiator->getNegotiationMethodInstance($method_id);
|
Chris@0
|
142 $weights[$method_id] = $method['weight'];
|
Chris@0
|
143 }
|
Chris@0
|
144 }
|
Chris@0
|
145 }
|
Chris@0
|
146 }
|
Chris@0
|
147
|
Chris@0
|
148 // Sort the processors list, so that their functions are called in the
|
Chris@0
|
149 // order specified by the weight of the methods.
|
Chris@0
|
150 uksort($this->processors[$scope], function ($method_id_a, $method_id_b) use ($weights) {
|
Chris@0
|
151 $a_weight = $weights[$method_id_a];
|
Chris@0
|
152 $b_weight = $weights[$method_id_b];
|
Chris@0
|
153
|
Chris@0
|
154 if ($a_weight == $b_weight) {
|
Chris@0
|
155 return 0;
|
Chris@0
|
156 }
|
Chris@0
|
157
|
Chris@0
|
158 return ($a_weight < $b_weight) ? -1 : 1;
|
Chris@0
|
159 });
|
Chris@0
|
160 }
|
Chris@0
|
161
|
Chris@0
|
162 /**
|
Chris@0
|
163 * Initializes the injected event subscriber with the language path processor.
|
Chris@0
|
164 *
|
Chris@0
|
165 * The language path processor service is registered only on multilingual
|
Chris@0
|
166 * site configuration, thus we inject it in the event subscriber only when
|
Chris@0
|
167 * it is initialized.
|
Chris@0
|
168 */
|
Chris@0
|
169 public function initConfigSubscriber() {
|
Chris@0
|
170 $this->configSubscriber->setPathProcessorLanguage($this);
|
Chris@0
|
171 }
|
Chris@0
|
172
|
Chris@0
|
173 /**
|
Chris@0
|
174 * Resets the collected processors instances.
|
Chris@0
|
175 */
|
Chris@0
|
176 public function reset() {
|
Chris@0
|
177 $this->processors = [];
|
Chris@0
|
178 }
|
Chris@0
|
179
|
Chris@0
|
180 }
|