Mercurial > hg > cmmr2012-drupal-site
comparison core/modules/language/src/LanguageNegotiator.php @ 0:c75dbcec494b
Initial commit from drush-created site
author | Chris Cannam |
---|---|
date | Thu, 05 Jul 2018 14:24:15 +0000 |
parents | |
children | 12f9dff5fda9 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:c75dbcec494b |
---|---|
1 <?php | |
2 | |
3 namespace Drupal\language; | |
4 | |
5 use Drupal\Component\Plugin\PluginManagerInterface; | |
6 use Drupal\Core\Config\ConfigFactoryInterface; | |
7 use Drupal\Core\Session\AccountInterface; | |
8 use Drupal\Core\Site\Settings; | |
9 use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUI; | |
10 use Symfony\Component\HttpFoundation\RequestStack; | |
11 | |
12 /** | |
13 * Class responsible for performing language negotiation. | |
14 */ | |
15 class LanguageNegotiator implements LanguageNegotiatorInterface { | |
16 | |
17 /** | |
18 * The language negotiation method plugin manager. | |
19 * | |
20 * @var \Drupal\Component\Plugin\PluginManagerInterface | |
21 */ | |
22 protected $negotiatorManager; | |
23 | |
24 /** | |
25 * The language manager. | |
26 * | |
27 * @var \Drupal\language\ConfigurableLanguageManagerInterface | |
28 */ | |
29 protected $languageManager; | |
30 | |
31 /** | |
32 * The configuration factory. | |
33 * | |
34 * @var \Drupal\Core\Config\ConfigFactoryInterface | |
35 */ | |
36 protected $configFactory; | |
37 | |
38 /** | |
39 * The settings instance. | |
40 * | |
41 * @var \Drupal\Core\Site\Settings | |
42 */ | |
43 protected $settings; | |
44 | |
45 /** | |
46 * The request stack object. | |
47 * | |
48 * @var \Symfony\Component\HttpFoundation\RequestStack | |
49 */ | |
50 protected $requestStack; | |
51 | |
52 /** | |
53 * The current active user. | |
54 * | |
55 * @var \Drupal\Core\Session\AccountInterface | |
56 */ | |
57 protected $currentUser; | |
58 | |
59 /** | |
60 * Local cache for language negotiation method instances. | |
61 * | |
62 * @var array | |
63 */ | |
64 protected $methods; | |
65 | |
66 /** | |
67 * An array of language objects keyed by method id. | |
68 * | |
69 * @var \Drupal\Core\Language\LanguageInterface[] | |
70 */ | |
71 protected $negotiatedLanguages = []; | |
72 | |
73 /** | |
74 * Constructs a new LanguageNegotiator object. | |
75 * | |
76 * @param \Drupal\language\ConfigurableLanguageManagerInterface $language_manager | |
77 * The language manager. | |
78 * @param \Drupal\Component\Plugin\PluginManagerInterface $negotiator_manager | |
79 * The language negotiation methods plugin manager | |
80 * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory | |
81 * The configuration factory. | |
82 * @param \Drupal\Core\Site\Settings $settings | |
83 * The settings instance. | |
84 */ | |
85 public function __construct(ConfigurableLanguageManagerInterface $language_manager, PluginManagerInterface $negotiator_manager, ConfigFactoryInterface $config_factory, Settings $settings, RequestStack $requestStack) { | |
86 $this->languageManager = $language_manager; | |
87 $this->negotiatorManager = $negotiator_manager; | |
88 $this->configFactory = $config_factory; | |
89 $this->settings = $settings; | |
90 $this->requestStack = $requestStack; | |
91 } | |
92 | |
93 /** | |
94 * Initializes the injected language manager with the negotiator. | |
95 * | |
96 * This should be called right after instantiating the negotiator to make it | |
97 * available to the language manager without introducing a circular | |
98 * dependency. | |
99 */ | |
100 public function initLanguageManager() { | |
101 $this->languageManager->setNegotiator($this); | |
102 } | |
103 | |
104 /** | |
105 * {@inheritdoc} | |
106 */ | |
107 public function reset() { | |
108 $this->negotiatedLanguages = []; | |
109 $this->methods = []; | |
110 } | |
111 | |
112 /** | |
113 * {@inheritdoc} | |
114 */ | |
115 public function setCurrentUser(AccountInterface $current_user) { | |
116 $this->currentUser = $current_user; | |
117 $this->reset(); | |
118 } | |
119 | |
120 /** | |
121 * {@inheritdoc} | |
122 */ | |
123 public function initializeType($type) { | |
124 $language = NULL; | |
125 | |
126 if ($this->currentUser) { | |
127 // Execute the language negotiation methods in the order they were set up | |
128 // and return the first valid language found. | |
129 foreach ($this->getEnabledNegotiators($type) as $method_id => $info) { | |
130 if (!isset($this->negotiatedLanguages[$method_id])) { | |
131 $this->negotiatedLanguages[$method_id] = $this->negotiateLanguage($type, $method_id); | |
132 } | |
133 | |
134 // Since objects are references, we need to return a clone to prevent | |
135 // the language negotiation method cache from being unintentionally | |
136 // altered. The same methods might be used with different language types | |
137 // based on configuration. | |
138 $language = !empty($this->negotiatedLanguages[$method_id]) ? clone($this->negotiatedLanguages[$method_id]) : NULL; | |
139 | |
140 if ($language) { | |
141 $this->getNegotiationMethodInstance($method_id)->persist($language); | |
142 break; | |
143 } | |
144 } | |
145 } | |
146 | |
147 if (!$language) { | |
148 // If no other language was found use the default one. | |
149 $language = $this->languageManager->getDefaultLanguage(); | |
150 $method_id = static::METHOD_ID; | |
151 } | |
152 | |
153 return [$method_id => $language]; | |
154 } | |
155 | |
156 /** | |
157 * Gets enabled detection methods for the provided language type. | |
158 * | |
159 * @param string $type | |
160 * The language type. | |
161 * | |
162 * @return array | |
163 * An array of enabled detection methods for the provided language type. | |
164 */ | |
165 protected function getEnabledNegotiators($type) { | |
166 return $this->configFactory->get('language.types')->get('negotiation.' . $type . '.enabled') ?: []; | |
167 } | |
168 | |
169 /** | |
170 * Performs language negotiation using the specified negotiation method. | |
171 * | |
172 * @param string $type | |
173 * The language type to be initialized. | |
174 * @param string $method_id | |
175 * The string identifier of the language negotiation method to use to detect | |
176 * language. | |
177 * | |
178 * @return \Drupal\Core\Language\LanguageInterface|null | |
179 * Negotiated language object for given type and method, FALSE otherwise. | |
180 */ | |
181 protected function negotiateLanguage($type, $method_id) { | |
182 $langcode = NULL; | |
183 $method = $this->negotiatorManager->getDefinition($method_id); | |
184 | |
185 if (!isset($method['types']) || in_array($type, $method['types'])) { | |
186 $langcode = $this->getNegotiationMethodInstance($method_id)->getLangcode($this->requestStack->getCurrentRequest()); | |
187 } | |
188 | |
189 $languages = $this->languageManager->getLanguages(); | |
190 return isset($languages[$langcode]) ? $languages[$langcode] : NULL; | |
191 } | |
192 | |
193 /** | |
194 * {@inheritdoc} | |
195 */ | |
196 public function getNegotiationMethods($type = NULL) { | |
197 $definitions = $this->negotiatorManager->getDefinitions(); | |
198 if (isset($type)) { | |
199 $enabled_methods = $this->getEnabledNegotiators($type); | |
200 $definitions = array_intersect_key($definitions, $enabled_methods); | |
201 } | |
202 return $definitions; | |
203 } | |
204 | |
205 /** | |
206 * {@inheritdoc} | |
207 */ | |
208 public function getNegotiationMethodInstance($method_id) { | |
209 if (!isset($this->methods[$method_id])) { | |
210 $instance = $this->negotiatorManager->createInstance($method_id, []); | |
211 $instance->setLanguageManager($this->languageManager); | |
212 $instance->setConfig($this->configFactory); | |
213 $instance->setCurrentUser($this->currentUser); | |
214 $this->methods[$method_id] = $instance; | |
215 } | |
216 return $this->methods[$method_id]; | |
217 } | |
218 | |
219 /** | |
220 * {@inheritdoc} | |
221 */ | |
222 public function getPrimaryNegotiationMethod($type) { | |
223 $enabled_methods = $this->getEnabledNegotiators($type); | |
224 return empty($enabled_methods) ? LanguageNegotiatorInterface::METHOD_ID : key($enabled_methods); | |
225 } | |
226 | |
227 /** | |
228 * {@inheritdoc} | |
229 */ | |
230 public function isNegotiationMethodEnabled($method_id, $type = NULL) { | |
231 $enabled = FALSE; | |
232 $language_types = !empty($type) ? [$type] : $this->languageManager->getLanguageTypes(); | |
233 | |
234 foreach ($language_types as $type) { | |
235 $enabled_methods = $this->getEnabledNegotiators($type); | |
236 if (isset($enabled_methods[$method_id])) { | |
237 $enabled = TRUE; | |
238 break; | |
239 } | |
240 } | |
241 | |
242 return $enabled; | |
243 } | |
244 | |
245 /** | |
246 * {@inheritdoc} | |
247 */ | |
248 public function saveConfiguration($type, $enabled_methods) { | |
249 // As configurable language types might have changed, we reset the cache. | |
250 $this->languageManager->reset(); | |
251 $definitions = $this->getNegotiationMethods(); | |
252 $default_types = $this->languageManager->getLanguageTypes(); | |
253 | |
254 // Order the language negotiation method list by weight. | |
255 asort($enabled_methods); | |
256 foreach ($enabled_methods as $method_id => $weight) { | |
257 if (isset($definitions[$method_id])) { | |
258 $method = $definitions[$method_id]; | |
259 // If the language negotiation method does not express any preference | |
260 // about types, make it available for any configurable type. | |
261 $types = array_flip(!empty($method['types']) ? $method['types'] : $default_types); | |
262 // Check whether the method is defined and has the right type. | |
263 if (!isset($types[$type])) { | |
264 unset($enabled_methods[$method_id]); | |
265 } | |
266 } | |
267 else { | |
268 unset($enabled_methods[$method_id]); | |
269 } | |
270 } | |
271 $this->configFactory->getEditable('language.types')->set('negotiation.' . $type . '.enabled', $enabled_methods)->save(); | |
272 } | |
273 | |
274 /** | |
275 * {@inheritdoc} | |
276 */ | |
277 public function purgeConfiguration() { | |
278 // Ensure that we are getting the defined language negotiation information. | |
279 // An invocation of \Drupal\Core\Extension\ModuleInstaller::install() or | |
280 // \Drupal\Core\Extension\ModuleInstaller::uninstall() could invalidate the | |
281 // cached information. | |
282 $this->negotiatorManager->clearCachedDefinitions(); | |
283 $this->languageManager->reset(); | |
284 foreach ($this->languageManager->getDefinedLanguageTypesInfo() as $type => $info) { | |
285 $this->saveConfiguration($type, $this->getEnabledNegotiators($type)); | |
286 } | |
287 } | |
288 | |
289 /** | |
290 * {@inheritdoc} | |
291 */ | |
292 public function updateConfiguration(array $types) { | |
293 // Ensure that we are getting the defined language negotiation information. | |
294 // An invocation of \Drupal\Core\Extension\ModuleInstaller::install() or | |
295 // \Drupal\Core\Extension\ModuleInstaller::uninstall() could invalidate the | |
296 // cached information. | |
297 $this->negotiatorManager->clearCachedDefinitions(); | |
298 $this->languageManager->reset(); | |
299 | |
300 $language_types = []; | |
301 $language_types_info = $this->languageManager->getDefinedLanguageTypesInfo(); | |
302 $method_definitions = $this->getNegotiationMethods(); | |
303 | |
304 foreach ($language_types_info as $type => $info) { | |
305 $configurable = in_array($type, $types); | |
306 | |
307 // The default language negotiation settings, if available, are stored in | |
308 // $info['fixed']. | |
309 $has_default_settings = !empty($info['fixed']); | |
310 // Check whether the language type is unlocked. Only the status of | |
311 // unlocked language types can be toggled between configurable and | |
312 // non-configurable. | |
313 if (empty($info['locked'])) { | |
314 if (!$configurable && !$has_default_settings) { | |
315 // If we have an unlocked non-configurable language type without | |
316 // default language negotiation settings, we use the values | |
317 // negotiated for the interface language which, should always be | |
318 // available. | |
319 $method_weights = [LanguageNegotiationUI::METHOD_ID]; | |
320 $method_weights = array_flip($method_weights); | |
321 $this->saveConfiguration($type, $method_weights); | |
322 } | |
323 } | |
324 else { | |
325 // The language type is locked. Locked language types with default | |
326 // settings are always considered non-configurable. In turn if default | |
327 // settings are missing, the language type is always considered | |
328 // configurable. | |
329 | |
330 // If the language type is locked we can just store its default language | |
331 // negotiation settings if it has some, since it is not configurable. | |
332 if ($has_default_settings) { | |
333 $method_weights = []; | |
334 // Default settings are in $info['fixed']. | |
335 | |
336 foreach ($info['fixed'] as $weight => $method_id) { | |
337 if (isset($method_definitions[$method_id])) { | |
338 $method_weights[$method_id] = $weight; | |
339 } | |
340 } | |
341 $this->saveConfiguration($type, $method_weights); | |
342 } | |
343 else { | |
344 // It was missing default settings, so force it to be configurable. | |
345 $configurable = TRUE; | |
346 } | |
347 } | |
348 | |
349 // Accumulate information for each language type so it can be saved later. | |
350 $language_types[$type] = $configurable; | |
351 } | |
352 | |
353 // Store the language type configuration. | |
354 $config = [ | |
355 'configurable' => array_keys(array_filter($language_types)), | |
356 'all' => array_keys($language_types), | |
357 ]; | |
358 $this->languageManager->saveLanguageTypesConfiguration($config); | |
359 } | |
360 | |
361 } |