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 * Constructs a PathProcessorLanguage object.
|
Chris@0
|
65 *
|
Chris@0
|
66 * @param \Drupal\Core\Config\ConfigFactoryInterface $config
|
Chris@0
|
67 * A config factory object for retrieving configuration settings.
|
Chris@0
|
68 * @param \Drupal\language\ConfigurableLanguageManagerInterface $language_manager
|
Chris@0
|
69 * The configurable language manager.
|
Chris@0
|
70 * @param \Drupal\language\LanguageNegotiatorInterface $negotiator
|
Chris@0
|
71 * The language negotiator.
|
Chris@0
|
72 * @param \Drupal\Core\Session\AccountInterface $current_user
|
Chris@0
|
73 * The current active user.
|
Chris@0
|
74 * @param \Drupal\language\EventSubscriber\ConfigSubscriber $config_subscriber
|
Chris@0
|
75 * The language configuration event subscriber.
|
Chris@0
|
76 */
|
Chris@0
|
77 public function __construct(ConfigFactoryInterface $config, ConfigurableLanguageManagerInterface $language_manager, LanguageNegotiatorInterface $negotiator, AccountInterface $current_user, ConfigSubscriber $config_subscriber) {
|
Chris@0
|
78 $this->config = $config;
|
Chris@0
|
79 $this->languageManager = $language_manager;
|
Chris@0
|
80 $this->negotiator = $negotiator;
|
Chris@0
|
81 $this->negotiator->setCurrentUser($current_user);
|
Chris@0
|
82 $this->configSubscriber = $config_subscriber;
|
Chris@0
|
83 }
|
Chris@0
|
84
|
Chris@0
|
85 /**
|
Chris@0
|
86 * {@inheritdoc}
|
Chris@0
|
87 */
|
Chris@0
|
88 public function processInbound($path, Request $request) {
|
Chris@0
|
89 if (!empty($path)) {
|
Chris@0
|
90 $scope = 'inbound';
|
Chris@0
|
91 if (!isset($this->processors[$scope])) {
|
Chris@0
|
92 $this->initProcessors($scope);
|
Chris@0
|
93 }
|
Chris@0
|
94 foreach ($this->processors[$scope] as $instance) {
|
Chris@0
|
95 $path = $instance->processInbound($path, $request);
|
Chris@0
|
96 }
|
Chris@0
|
97 }
|
Chris@0
|
98 return $path;
|
Chris@0
|
99 }
|
Chris@0
|
100
|
Chris@0
|
101 /**
|
Chris@0
|
102 * {@inheritdoc}
|
Chris@0
|
103 */
|
Chris@0
|
104 public function processOutbound($path, &$options = [], Request $request = NULL, BubbleableMetadata $bubbleable_metadata = NULL) {
|
Chris@0
|
105 if (!isset($this->multilingual)) {
|
Chris@0
|
106 $this->multilingual = $this->languageManager->isMultilingual();
|
Chris@0
|
107 }
|
Chris@0
|
108 if ($this->multilingual) {
|
Chris@0
|
109 $this->negotiator->reset();
|
Chris@0
|
110 $scope = 'outbound';
|
Chris@0
|
111 if (!isset($this->processors[$scope])) {
|
Chris@0
|
112 $this->initProcessors($scope);
|
Chris@0
|
113 }
|
Chris@0
|
114 foreach ($this->processors[$scope] as $instance) {
|
Chris@0
|
115 $path = $instance->processOutbound($path, $options, $request, $bubbleable_metadata);
|
Chris@0
|
116 }
|
Chris@0
|
117 // No language dependent path allowed in this mode.
|
Chris@0
|
118 if (empty($this->processors[$scope])) {
|
Chris@0
|
119 unset($options['language']);
|
Chris@0
|
120 }
|
Chris@0
|
121 }
|
Chris@0
|
122 return $path;
|
Chris@0
|
123 }
|
Chris@0
|
124
|
Chris@0
|
125 /**
|
Chris@0
|
126 * Initializes the local cache for language path processors.
|
Chris@0
|
127 *
|
Chris@0
|
128 * @param string $scope
|
Chris@0
|
129 * The scope of the processors: "inbound" or "outbound".
|
Chris@0
|
130 */
|
Chris@0
|
131 protected function initProcessors($scope) {
|
Chris@0
|
132 $interface = '\Drupal\Core\PathProcessor\\' . Unicode::ucfirst($scope) . 'PathProcessorInterface';
|
Chris@0
|
133 $this->processors[$scope] = [];
|
Chris@0
|
134 $weights = [];
|
Chris@0
|
135 foreach ($this->languageManager->getLanguageTypes() as $type) {
|
Chris@0
|
136 foreach ($this->negotiator->getNegotiationMethods($type) as $method_id => $method) {
|
Chris@0
|
137 if (!isset($this->processors[$scope][$method_id])) {
|
Chris@0
|
138 $reflector = new \ReflectionClass($method['class']);
|
Chris@0
|
139 if ($reflector->implementsInterface($interface)) {
|
Chris@0
|
140 $this->processors[$scope][$method_id] = $this->negotiator->getNegotiationMethodInstance($method_id);
|
Chris@0
|
141 $weights[$method_id] = $method['weight'];
|
Chris@0
|
142 }
|
Chris@0
|
143 }
|
Chris@0
|
144 }
|
Chris@0
|
145 }
|
Chris@0
|
146
|
Chris@0
|
147 // Sort the processors list, so that their functions are called in the
|
Chris@0
|
148 // order specified by the weight of the methods.
|
Chris@0
|
149 uksort($this->processors[$scope], function ($method_id_a, $method_id_b) use ($weights) {
|
Chris@0
|
150 $a_weight = $weights[$method_id_a];
|
Chris@0
|
151 $b_weight = $weights[$method_id_b];
|
Chris@0
|
152
|
Chris@0
|
153 if ($a_weight == $b_weight) {
|
Chris@0
|
154 return 0;
|
Chris@0
|
155 }
|
Chris@0
|
156
|
Chris@0
|
157 return ($a_weight < $b_weight) ? -1 : 1;
|
Chris@0
|
158 });
|
Chris@0
|
159 }
|
Chris@0
|
160
|
Chris@0
|
161 /**
|
Chris@0
|
162 * Initializes the injected event subscriber with the language path processor.
|
Chris@0
|
163 *
|
Chris@0
|
164 * The language path processor service is registered only on multilingual
|
Chris@0
|
165 * site configuration, thus we inject it in the event subscriber only when
|
Chris@0
|
166 * it is initialized.
|
Chris@0
|
167 */
|
Chris@0
|
168 public function initConfigSubscriber() {
|
Chris@0
|
169 $this->configSubscriber->setPathProcessorLanguage($this);
|
Chris@0
|
170 }
|
Chris@0
|
171
|
Chris@0
|
172 /**
|
Chris@0
|
173 * Resets the collected processors instances.
|
Chris@0
|
174 */
|
Chris@0
|
175 public function reset() {
|
Chris@0
|
176 $this->processors = [];
|
Chris@0
|
177 }
|
Chris@0
|
178
|
Chris@0
|
179 }
|