Mercurial > hg > isophonics-drupal-site
comparison core/lib/Drupal/Core/Utility/UnroutedUrlAssembler.php @ 0:4c8ae668cc8c
Initial import (non-working)
author | Chris Cannam |
---|---|
date | Wed, 29 Nov 2017 16:09:58 +0000 |
parents | |
children | c2387f117808 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4c8ae668cc8c |
---|---|
1 <?php | |
2 | |
3 namespace Drupal\Core\Utility; | |
4 | |
5 use Drupal\Component\Utility\UrlHelper; | |
6 use Drupal\Core\GeneratedUrl; | |
7 use Drupal\Core\PathProcessor\OutboundPathProcessorInterface; | |
8 use Symfony\Component\HttpFoundation\RequestStack; | |
9 | |
10 /** | |
11 * Provides a way to build external or non Drupal local domain URLs. | |
12 * | |
13 * It takes into account configured safe HTTP protocols. | |
14 */ | |
15 class UnroutedUrlAssembler implements UnroutedUrlAssemblerInterface { | |
16 | |
17 /** | |
18 * A request stack object. | |
19 * | |
20 * @var \Symfony\Component\HttpFoundation\RequestStack | |
21 */ | |
22 protected $requestStack; | |
23 | |
24 /** | |
25 * The outbound path processor. | |
26 * | |
27 * @var \Drupal\Core\PathProcessor\OutboundPathProcessorInterface | |
28 */ | |
29 protected $pathProcessor; | |
30 | |
31 /** | |
32 * Constructs a new unroutedUrlAssembler object. | |
33 * | |
34 * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack | |
35 * A request stack object. | |
36 * @param \Drupal\Core\PathProcessor\OutboundPathProcessorInterface $path_processor | |
37 * The output path processor. | |
38 * @param string[] $filter_protocols | |
39 * (optional) An array of protocols allowed for URL generation. | |
40 */ | |
41 public function __construct(RequestStack $request_stack, OutboundPathProcessorInterface $path_processor, array $filter_protocols = ['http', 'https']) { | |
42 UrlHelper::setAllowedProtocols($filter_protocols); | |
43 $this->requestStack = $request_stack; | |
44 $this->pathProcessor = $path_processor; | |
45 } | |
46 | |
47 /** | |
48 * {@inheritdoc} | |
49 * | |
50 * This is a helper function that calls buildExternalUrl() or buildLocalUrl() | |
51 * based on a check of whether the path is a valid external URL. | |
52 */ | |
53 public function assemble($uri, array $options = [], $collect_bubbleable_metadata = FALSE) { | |
54 // Note that UrlHelper::isExternal will return FALSE if the $uri has a | |
55 // disallowed protocol. This is later made safe since we always add at | |
56 // least a leading slash. | |
57 if (parse_url($uri, PHP_URL_SCHEME) === 'base') { | |
58 return $this->buildLocalUrl($uri, $options, $collect_bubbleable_metadata); | |
59 } | |
60 elseif (UrlHelper::isExternal($uri)) { | |
61 // UrlHelper::isExternal() only returns true for safe protocols. | |
62 return $this->buildExternalUrl($uri, $options, $collect_bubbleable_metadata); | |
63 } | |
64 throw new \InvalidArgumentException("The URI '$uri' is invalid. You must use a valid URI scheme. Use base: for a path, e.g., to a Drupal file that needs the base path. Do not use this for internal paths controlled by Drupal."); | |
65 } | |
66 | |
67 /** | |
68 * {@inheritdoc} | |
69 */ | |
70 protected function buildExternalUrl($uri, array $options = [], $collect_bubbleable_metadata = FALSE) { | |
71 $this->addOptionDefaults($options); | |
72 // Split off the fragment. | |
73 if (strpos($uri, '#') !== FALSE) { | |
74 list($uri, $old_fragment) = explode('#', $uri, 2); | |
75 // If $options contains no fragment, take it over from the path. | |
76 if (isset($old_fragment) && !$options['fragment']) { | |
77 $options['fragment'] = '#' . $old_fragment; | |
78 } | |
79 } | |
80 | |
81 if (isset($options['https'])) { | |
82 if ($options['https'] === TRUE) { | |
83 $uri = str_replace('http://', 'https://', $uri); | |
84 } | |
85 elseif ($options['https'] === FALSE) { | |
86 $uri = str_replace('https://', 'http://', $uri); | |
87 } | |
88 } | |
89 // Append the query. | |
90 if ($options['query']) { | |
91 $uri .= (strpos($uri, '?') !== FALSE ? '&' : '?') . UrlHelper::buildQuery($options['query']); | |
92 } | |
93 // Reassemble. | |
94 $url = $uri . $options['fragment']; | |
95 return $collect_bubbleable_metadata ? (new GeneratedUrl())->setGeneratedUrl($url) : $url; | |
96 } | |
97 | |
98 /** | |
99 * {@inheritdoc} | |
100 */ | |
101 protected function buildLocalUrl($uri, array $options = [], $collect_bubbleable_metadata = FALSE) { | |
102 $generated_url = $collect_bubbleable_metadata ? new GeneratedUrl() : NULL; | |
103 | |
104 $this->addOptionDefaults($options); | |
105 $request = $this->requestStack->getCurrentRequest(); | |
106 | |
107 // Remove the base: scheme. | |
108 // @todo Consider using a class constant for this in | |
109 // https://www.drupal.org/node/2417459 | |
110 $uri = substr($uri, 5); | |
111 | |
112 // Allow (outbound) path processing, if needed. A valid use case is the path | |
113 // alias overview form: | |
114 // @see \Drupal\path\Controller\PathController::adminOverview(). | |
115 if (!empty($options['path_processing'])) { | |
116 // Do not pass the request, since this is a special case and we do not | |
117 // want to include e.g. the request language in the processing. | |
118 $uri = $this->pathProcessor->processOutbound($uri, $options, NULL, $generated_url); | |
119 } | |
120 // Strip leading slashes from internal paths to prevent them becoming | |
121 // external URLs without protocol. /example.com should not be turned into | |
122 // //example.com. | |
123 $uri = ltrim($uri, '/'); | |
124 | |
125 // Add any subdirectory where Drupal is installed. | |
126 $current_base_path = $request->getBasePath() . '/'; | |
127 | |
128 if ($options['absolute']) { | |
129 $current_base_url = $request->getSchemeAndHttpHost() . $current_base_path; | |
130 if (isset($options['https'])) { | |
131 if (!empty($options['https'])) { | |
132 $base = str_replace('http://', 'https://', $current_base_url); | |
133 $options['absolute'] = TRUE; | |
134 } | |
135 else { | |
136 $base = str_replace('https://', 'http://', $current_base_url); | |
137 $options['absolute'] = TRUE; | |
138 } | |
139 } | |
140 else { | |
141 $base = $current_base_url; | |
142 } | |
143 if ($collect_bubbleable_metadata) { | |
144 $generated_url->addCacheContexts(['url.site']); | |
145 } | |
146 } | |
147 else { | |
148 $base = $current_base_path; | |
149 } | |
150 | |
151 $prefix = empty($uri) ? rtrim($options['prefix'], '/') : $options['prefix']; | |
152 | |
153 $uri = str_replace('%2F', '/', rawurlencode($prefix . $uri)); | |
154 $query = $options['query'] ? ('?' . UrlHelper::buildQuery($options['query'])) : ''; | |
155 $url = $base . $options['script'] . $uri . $query . $options['fragment']; | |
156 return $collect_bubbleable_metadata ? $generated_url->setGeneratedUrl($url) : $url; | |
157 } | |
158 | |
159 /** | |
160 * Merges in default defaults | |
161 * | |
162 * @param array $options | |
163 * The options to merge in the defaults. | |
164 */ | |
165 protected function addOptionDefaults(array &$options) { | |
166 $request = $this->requestStack->getCurrentRequest(); | |
167 $current_base_path = $request->getBasePath() . '/'; | |
168 $current_script_path = ''; | |
169 $base_path_with_script = $request->getBaseUrl(); | |
170 | |
171 // If the current request was made with the script name (eg, index.php) in | |
172 // it, then extract it, making sure the leading / is gone, and a trailing / | |
173 // is added, to allow simple string concatenation with other parts. | |
174 if (!empty($base_path_with_script)) { | |
175 $script_name = $request->getScriptName(); | |
176 if (strpos($base_path_with_script, $script_name) !== FALSE) { | |
177 $current_script_path = ltrim(substr($script_name, strlen($current_base_path)), '/') . '/'; | |
178 } | |
179 } | |
180 | |
181 // Merge in defaults. | |
182 $options += [ | |
183 'fragment' => '', | |
184 'query' => [], | |
185 'absolute' => FALSE, | |
186 'prefix' => '', | |
187 'script' => $current_script_path, | |
188 ]; | |
189 | |
190 if (isset($options['fragment']) && $options['fragment'] !== '') { | |
191 $options['fragment'] = '#' . $options['fragment']; | |
192 } | |
193 } | |
194 | |
195 } |