1 | <?php |
||||
2 | /** |
||||
3 | * @link https://www.yiiframework.com/ |
||||
4 | * @copyright Copyright (c) 2008 Yii Software LLC |
||||
5 | * @license https://www.yiiframework.com/license/ |
||||
6 | */ |
||||
7 | |||||
8 | namespace yii\web; |
||||
9 | |||||
10 | use Yii; |
||||
11 | use yii\base\Component; |
||||
12 | use yii\base\InvalidConfigException; |
||||
13 | use yii\caching\CacheInterface; |
||||
14 | use yii\di\Instance; |
||||
15 | use yii\helpers\Url; |
||||
16 | |||||
17 | /** |
||||
18 | * UrlManager handles HTTP request parsing and creation of URLs based on a set of rules. |
||||
19 | * |
||||
20 | * UrlManager is configured as an application component in [[\yii\base\Application]] by default. |
||||
21 | * You can access that instance via `Yii::$app->urlManager`. |
||||
22 | * |
||||
23 | * You can modify its configuration by adding an array to your application config under `components` |
||||
24 | * as it is shown in the following example: |
||||
25 | * |
||||
26 | * ```php |
||||
27 | * 'urlManager' => [ |
||||
28 | * 'enablePrettyUrl' => true, |
||||
29 | * 'rules' => [ |
||||
30 | * // your rules go here |
||||
31 | * ], |
||||
32 | * // ... |
||||
33 | * ] |
||||
34 | * ``` |
||||
35 | * |
||||
36 | * Rules are classes implementing the [[UrlRuleInterface]], by default that is [[UrlRule]]. |
||||
37 | * For nesting rules, there is also a [[GroupUrlRule]] class. |
||||
38 | * |
||||
39 | * For more details and usage information on UrlManager, see the [guide article on routing](guide:runtime-routing). |
||||
40 | * |
||||
41 | * @property string $baseUrl The base URL that is used by [[createUrl()]] to prepend to created URLs. |
||||
42 | * @property string $hostInfo The host info (e.g. `https://www.example.com`) that is used by |
||||
43 | * [[createAbsoluteUrl()]] to prepend to created URLs. |
||||
44 | * @property string $scriptUrl The entry script URL that is used by [[createUrl()]] to prepend to created |
||||
45 | * URLs. |
||||
46 | * |
||||
47 | * @author Qiang Xue <[email protected]> |
||||
48 | * @since 2.0 |
||||
49 | */ |
||||
50 | class UrlManager extends Component |
||||
51 | { |
||||
52 | /** |
||||
53 | * @var bool whether to enable pretty URLs. Instead of putting all parameters in the query |
||||
54 | * string part of a URL, pretty URLs allow using path info to represent some of the parameters |
||||
55 | * and can thus produce more user-friendly URLs, such as "/news/Yii-is-released", instead of |
||||
56 | * "/index.php?r=news%2Fview&id=100". |
||||
57 | */ |
||||
58 | public $enablePrettyUrl = false; |
||||
59 | /** |
||||
60 | * @var bool whether to enable strict parsing. If strict parsing is enabled, the incoming |
||||
61 | * requested URL must match at least one of the [[rules]] in order to be treated as a valid request. |
||||
62 | * Otherwise, the path info part of the request will be treated as the requested route. |
||||
63 | * This property is used only when [[enablePrettyUrl]] is `true`. |
||||
64 | */ |
||||
65 | public $enableStrictParsing = false; |
||||
66 | /** |
||||
67 | * @var array the rules for creating and parsing URLs when [[enablePrettyUrl]] is `true`. |
||||
68 | * This property is used only if [[enablePrettyUrl]] is `true`. Each element in the array |
||||
69 | * is the configuration array for creating a single URL rule. The configuration will |
||||
70 | * be merged with [[ruleConfig]] first before it is used for creating the rule object. |
||||
71 | * |
||||
72 | * A special shortcut format can be used if a rule only specifies [[UrlRule::pattern|pattern]] |
||||
73 | * and [[UrlRule::route|route]]: `'pattern' => 'route'`. That is, instead of using a configuration |
||||
74 | * array, one can use the key to represent the pattern and the value the corresponding route. |
||||
75 | * For example, `'post/<id:\d+>' => 'post/view'`. |
||||
76 | * |
||||
77 | * For RESTful routing the mentioned shortcut format also allows you to specify the |
||||
78 | * [[UrlRule::verb|HTTP verb]] that the rule should apply for. |
||||
79 | * You can do that by prepending it to the pattern, separated by space. |
||||
80 | * For example, `'PUT post/<id:\d+>' => 'post/update'`. |
||||
81 | * You may specify multiple verbs by separating them with comma |
||||
82 | * like this: `'POST,PUT post/index' => 'post/create'`. |
||||
83 | * The supported verbs in the shortcut format are: GET, HEAD, POST, PUT, PATCH and DELETE. |
||||
84 | * Note that [[UrlRule::mode|mode]] will be set to PARSING_ONLY when specifying verb in this way |
||||
85 | * so you normally would not specify a verb for normal GET request. |
||||
86 | * |
||||
87 | * Here is an example configuration for RESTful CRUD controller: |
||||
88 | * |
||||
89 | * ```php |
||||
90 | * [ |
||||
91 | * 'dashboard' => 'site/index', |
||||
92 | * |
||||
93 | * 'POST <controller:[\w-]+>' => '<controller>/create', |
||||
94 | * '<controller:[\w-]+>s' => '<controller>/index', |
||||
95 | * |
||||
96 | * 'PUT <controller:[\w-]+>/<id:\d+>' => '<controller>/update', |
||||
97 | * 'DELETE <controller:[\w-]+>/<id:\d+>' => '<controller>/delete', |
||||
98 | * '<controller:[\w-]+>/<id:\d+>' => '<controller>/view', |
||||
99 | * ]; |
||||
100 | * ``` |
||||
101 | * |
||||
102 | * Note that if you modify this property after the UrlManager object is created, make sure |
||||
103 | * you populate the array with rule objects instead of rule configurations. |
||||
104 | */ |
||||
105 | public $rules = []; |
||||
106 | /** |
||||
107 | * @var string the URL suffix used when [[enablePrettyUrl]] is `true`. |
||||
108 | * For example, ".html" can be used so that the URL looks like pointing to a static HTML page. |
||||
109 | * This property is used only if [[enablePrettyUrl]] is `true`. |
||||
110 | */ |
||||
111 | public $suffix; |
||||
112 | /** |
||||
113 | * @var bool whether to show entry script name in the constructed URL. Defaults to `true`. |
||||
114 | * This property is used only if [[enablePrettyUrl]] is `true`. |
||||
115 | */ |
||||
116 | public $showScriptName = true; |
||||
117 | /** |
||||
118 | * @var string the GET parameter name for route. This property is used only if [[enablePrettyUrl]] is `false`. |
||||
119 | */ |
||||
120 | public $routeParam = 'r'; |
||||
121 | /** |
||||
122 | * @var CacheInterface|array|string|bool the cache object or the application component ID of the cache object. |
||||
123 | * This can also be an array that is used to create a [[CacheInterface]] instance in case you do not want to use |
||||
124 | * an application component. |
||||
125 | * Compiled URL rules will be cached through this cache object, if it is available. |
||||
126 | * |
||||
127 | * After the UrlManager object is created, if you want to change this property, |
||||
128 | * you should only assign it with a cache object. |
||||
129 | * Set this property to `false` or `null` if you do not want to cache the URL rules. |
||||
130 | * |
||||
131 | * Cache entries are stored for the time set by [[\yii\caching\Cache::$defaultDuration|$defaultDuration]] in |
||||
132 | * the cache configuration, which is unlimited by default. You may want to tune this value if your [[rules]] |
||||
133 | * change frequently. |
||||
134 | */ |
||||
135 | public $cache = 'cache'; |
||||
136 | /** |
||||
137 | * @var array the default configuration of URL rules. Individual rule configurations |
||||
138 | * specified via [[rules]] will take precedence when the same property of the rule is configured. |
||||
139 | */ |
||||
140 | public $ruleConfig = ['class' => 'yii\web\UrlRule']; |
||||
141 | /** |
||||
142 | * @var UrlNormalizer|array|string|false the configuration for [[UrlNormalizer]] used by this UrlManager. |
||||
143 | * The default value is `false`, which means normalization will be skipped. |
||||
144 | * If you wish to enable URL normalization, you should configure this property manually. |
||||
145 | * For example: |
||||
146 | * |
||||
147 | * ```php |
||||
148 | * [ |
||||
149 | * 'class' => 'yii\web\UrlNormalizer', |
||||
150 | * 'collapseSlashes' => true, |
||||
151 | * 'normalizeTrailingSlash' => true, |
||||
152 | * ] |
||||
153 | * ``` |
||||
154 | * |
||||
155 | * @since 2.0.10 |
||||
156 | */ |
||||
157 | public $normalizer = false; |
||||
158 | |||||
159 | /** |
||||
160 | * @var string the cache key for cached rules |
||||
161 | * @since 2.0.8 |
||||
162 | */ |
||||
163 | protected $cacheKey = __CLASS__; |
||||
164 | |||||
165 | private $_baseUrl; |
||||
166 | private $_scriptUrl; |
||||
167 | private $_hostInfo; |
||||
168 | private $_ruleCache; |
||||
169 | |||||
170 | |||||
171 | /** |
||||
172 | * Initializes UrlManager. |
||||
173 | */ |
||||
174 | 207 | public function init() |
|||
175 | { |
||||
176 | 207 | parent::init(); |
|||
177 | |||||
178 | 207 | if ($this->normalizer !== false) { |
|||
179 | 3 | $this->normalizer = Yii::createObject($this->normalizer); |
|||
180 | 3 | if (!$this->normalizer instanceof UrlNormalizer) { |
|||
181 | throw new InvalidConfigException('`' . get_class($this) . '::normalizer` should be an instance of `' . UrlNormalizer::class . '` or its DI compatible configuration.'); |
||||
182 | } |
||||
183 | } |
||||
184 | |||||
185 | 207 | if (!$this->enablePrettyUrl) { |
|||
186 | 106 | return; |
|||
187 | } |
||||
188 | |||||
189 | 101 | if (!empty($this->rules)) { |
|||
190 | 79 | $this->rules = $this->buildRules($this->rules); |
|||
191 | } |
||||
192 | } |
||||
193 | |||||
194 | /** |
||||
195 | * Adds additional URL rules. |
||||
196 | * |
||||
197 | * This method will call [[buildRules()]] to parse the given rule declarations and then append or insert |
||||
198 | * them to the existing [[rules]]. |
||||
199 | * |
||||
200 | * Note that if [[enablePrettyUrl]] is `false`, this method will do nothing. |
||||
201 | * |
||||
202 | * @param array $rules the new rules to be added. Each array element represents a single rule declaration. |
||||
203 | * Please refer to [[rules]] for the acceptable rule format. |
||||
204 | * @param bool $append whether to add the new rules by appending them to the end of the existing rules. |
||||
205 | */ |
||||
206 | 3 | public function addRules($rules, $append = true) |
|||
207 | { |
||||
208 | 3 | if (!$this->enablePrettyUrl) { |
|||
209 | return; |
||||
210 | } |
||||
211 | 3 | $rules = $this->buildRules($rules); |
|||
212 | 3 | if ($append) { |
|||
213 | 2 | $this->rules = array_merge($this->rules, $rules); |
|||
214 | } else { |
||||
215 | 1 | $this->rules = array_merge($rules, $this->rules); |
|||
216 | } |
||||
217 | } |
||||
218 | |||||
219 | /** |
||||
220 | * Builds URL rule objects from the given rule declarations. |
||||
221 | * |
||||
222 | * @param array $ruleDeclarations the rule declarations. Each array element represents a single rule declaration. |
||||
223 | * Please refer to [[rules]] for the acceptable rule formats. |
||||
224 | * @return UrlRuleInterface[] the rule objects built from the given rule declarations |
||||
225 | * @throws InvalidConfigException if a rule declaration is invalid |
||||
226 | */ |
||||
227 | 79 | protected function buildRules($ruleDeclarations) |
|||
228 | { |
||||
229 | 79 | $builtRules = $this->getBuiltRulesFromCache($ruleDeclarations); |
|||
230 | 79 | if ($builtRules !== false) { |
|||
231 | 1 | return $builtRules; |
|||
232 | } |
||||
233 | |||||
234 | 78 | $builtRules = []; |
|||
235 | 78 | $verbs = 'GET|HEAD|POST|PUT|PATCH|DELETE|OPTIONS'; |
|||
236 | 78 | foreach ($ruleDeclarations as $key => $rule) { |
|||
237 | 78 | if (is_string($rule)) { |
|||
238 | 71 | $rule = ['route' => $rule]; |
|||
239 | 71 | if (preg_match("/^((?:($verbs),)*($verbs))\\s+(.*)$/", $key, $matches)) { |
|||
240 | 9 | $rule['verb'] = explode(',', $matches[1]); |
|||
241 | 9 | $key = $matches[4]; |
|||
242 | } |
||||
243 | 71 | $rule['pattern'] = $key; |
|||
244 | } |
||||
245 | 78 | if (is_array($rule)) { |
|||
246 | 76 | $rule = Yii::createObject(array_merge($this->ruleConfig, $rule)); |
|||
247 | } |
||||
248 | 78 | if (!$rule instanceof UrlRuleInterface) { |
|||
249 | throw new InvalidConfigException('URL rule class must implement UrlRuleInterface.'); |
||||
250 | } |
||||
251 | 78 | $builtRules[] = $rule; |
|||
252 | } |
||||
253 | |||||
254 | 78 | $this->setBuiltRulesCache($ruleDeclarations, $builtRules); |
|||
255 | |||||
256 | 78 | return $builtRules; |
|||
257 | } |
||||
258 | |||||
259 | /** |
||||
260 | * @return CacheInterface|null|bool |
||||
261 | */ |
||||
262 | 79 | private function ensureCache() |
|||
263 | { |
||||
264 | 79 | if (!$this->cache instanceof CacheInterface && $this->cache !== false && $this->cache !== null) { |
|||
265 | try { |
||||
266 | 2 | $this->cache = Instance::ensure($this->cache, 'yii\caching\CacheInterface'); |
|||
267 | } catch (InvalidConfigException $e) { |
||||
268 | Yii::warning('Unable to use cache for URL manager: ' . $e->getMessage()); |
||||
269 | $this->cache = null; |
||||
270 | } |
||||
271 | } |
||||
272 | |||||
273 | 79 | return $this->cache; |
|||
0 ignored issues
–
show
Bug
Best Practice
introduced
by
![]() |
|||||
274 | } |
||||
275 | |||||
276 | /** |
||||
277 | * Stores $builtRules to cache, using $rulesDeclaration as a part of cache key. |
||||
278 | * |
||||
279 | * @param array $ruleDeclarations the rule declarations. Each array element represents a single rule declaration. |
||||
280 | * Please refer to [[rules]] for the acceptable rule formats. |
||||
281 | * @param UrlRuleInterface[] $builtRules the rule objects built from the given rule declarations. |
||||
282 | * @return bool whether the value is successfully stored into cache |
||||
283 | * @since 2.0.14 |
||||
284 | */ |
||||
285 | 78 | protected function setBuiltRulesCache($ruleDeclarations, $builtRules) |
|||
286 | { |
||||
287 | 78 | $cache = $this->ensureCache(); |
|||
288 | 78 | if (!$cache) { |
|||
0 ignored issues
–
show
|
|||||
289 | 75 | return false; |
|||
290 | } |
||||
291 | |||||
292 | 3 | return $cache->set([$this->cacheKey, $this->ruleConfig, $ruleDeclarations], $builtRules); |
|||
293 | } |
||||
294 | |||||
295 | /** |
||||
296 | * Provides the built URL rules that are associated with the $ruleDeclarations from cache. |
||||
297 | * |
||||
298 | * @param array $ruleDeclarations the rule declarations. Each array element represents a single rule declaration. |
||||
299 | * Please refer to [[rules]] for the acceptable rule formats. |
||||
300 | * @return UrlRuleInterface[]|false the rule objects built from the given rule declarations or boolean `false` when |
||||
301 | * there are no cache items for this definition exists. |
||||
302 | * @since 2.0.14 |
||||
303 | */ |
||||
304 | 79 | protected function getBuiltRulesFromCache($ruleDeclarations) |
|||
305 | { |
||||
306 | 79 | $cache = $this->ensureCache(); |
|||
307 | 79 | if (!$cache) { |
|||
0 ignored issues
–
show
|
|||||
308 | 75 | return false; |
|||
309 | } |
||||
310 | |||||
311 | 4 | return $cache->get([$this->cacheKey, $this->ruleConfig, $ruleDeclarations]); |
|||
312 | } |
||||
313 | |||||
314 | /** |
||||
315 | * Parses the user request. |
||||
316 | * @param Request $request the request component |
||||
317 | * @return array|bool the route and the associated parameters. The latter is always empty |
||||
318 | * if [[enablePrettyUrl]] is `false`. `false` is returned if the current request cannot be successfully parsed. |
||||
319 | */ |
||||
320 | 17 | public function parseRequest($request) |
|||
321 | { |
||||
322 | 17 | if ($this->enablePrettyUrl) { |
|||
323 | /** @var UrlRule $rule */ |
||||
324 | 14 | foreach ($this->rules as $rule) { |
|||
325 | 10 | $result = $rule->parseRequest($this, $request); |
|||
326 | 10 | if (YII_DEBUG) { |
|||
327 | 10 | Yii::debug([ |
|||
328 | 10 | 'rule' => method_exists($rule, '__toString') ? $rule->__toString() : get_class($rule), |
|||
329 | 10 | 'match' => $result !== false, |
|||
330 | 10 | 'parent' => null, |
|||
331 | 10 | ], __METHOD__); |
|||
332 | } |
||||
333 | 10 | if ($result !== false) { |
|||
334 | 10 | return $result; |
|||
335 | } |
||||
336 | } |
||||
337 | |||||
338 | 11 | if ($this->enableStrictParsing) { |
|||
339 | 4 | return false; |
|||
340 | } |
||||
341 | |||||
342 | 7 | Yii::debug('No matching URL rules. Using default URL parsing logic.', __METHOD__); |
|||
343 | |||||
344 | 7 | $suffix = (string) $this->suffix; |
|||
345 | 7 | $pathInfo = $request->getPathInfo(); |
|||
346 | 7 | $normalized = false; |
|||
347 | 7 | if ($this->normalizer !== false) { |
|||
348 | 1 | $pathInfo = $this->normalizer->normalizePathInfo($pathInfo, $suffix, $normalized); |
|||
349 | } |
||||
350 | 7 | if ($suffix !== '' && $pathInfo !== '') { |
|||
351 | 4 | $n = strlen($this->suffix); |
|||
352 | 4 | if (substr_compare($pathInfo, $this->suffix, -$n, $n) === 0) { |
|||
353 | 4 | $pathInfo = substr($pathInfo, 0, -$n); |
|||
354 | 4 | if ($pathInfo === '') { |
|||
355 | // suffix alone is not allowed |
||||
356 | 4 | return false; |
|||
357 | } |
||||
358 | } else { |
||||
359 | // suffix doesn't match |
||||
360 | 4 | return false; |
|||
361 | } |
||||
362 | } |
||||
363 | |||||
364 | 7 | if ($normalized) { |
|||
365 | // pathInfo was changed by normalizer - we need also normalize route |
||||
366 | 1 | return $this->normalizer->normalizeRoute([$pathInfo, []]); |
|||
367 | } |
||||
368 | |||||
369 | 6 | return [$pathInfo, []]; |
|||
370 | } |
||||
371 | |||||
372 | 3 | Yii::debug('Pretty URL not enabled. Using default URL parsing logic.', __METHOD__); |
|||
373 | 3 | $route = $request->getQueryParam($this->routeParam, ''); |
|||
374 | 3 | if (is_array($route)) { |
|||
375 | 3 | $route = ''; |
|||
376 | } |
||||
377 | |||||
378 | 3 | return [(string) $route, []]; |
|||
379 | } |
||||
380 | |||||
381 | /** |
||||
382 | * Creates a URL using the given route and query parameters. |
||||
383 | * |
||||
384 | * You may specify the route as a string, e.g., `site/index`. You may also use an array |
||||
385 | * if you want to specify additional query parameters for the URL being created. The |
||||
386 | * array format must be: |
||||
387 | * |
||||
388 | * ```php |
||||
389 | * // generates: /index.php?r=site%2Findex¶m1=value1¶m2=value2 |
||||
390 | * ['site/index', 'param1' => 'value1', 'param2' => 'value2'] |
||||
391 | * ``` |
||||
392 | * |
||||
393 | * If you want to create a URL with an anchor, you can use the array format with a `#` parameter. |
||||
394 | * For example, |
||||
395 | * |
||||
396 | * ```php |
||||
397 | * // generates: /index.php?r=site%2Findex¶m1=value1#name |
||||
398 | * ['site/index', 'param1' => 'value1', '#' => 'name'] |
||||
399 | * ``` |
||||
400 | * |
||||
401 | * The URL created is a relative one. Use [[createAbsoluteUrl()]] to create an absolute URL. |
||||
402 | * |
||||
403 | * Note that unlike [[\yii\helpers\Url::toRoute()]], this method always treats the given route |
||||
404 | * as an absolute route. |
||||
405 | * |
||||
406 | * @param string|array $params use a string to represent a route (e.g. `site/index`), |
||||
407 | * or an array to represent a route with query parameters (e.g. `['site/index', 'param1' => 'value1']`). |
||||
408 | * @return string the created URL |
||||
409 | */ |
||||
410 | 160 | public function createUrl($params) |
|||
411 | { |
||||
412 | 160 | $params = (array) $params; |
|||
413 | 160 | $anchor = isset($params['#']) ? '#' . $params['#'] : ''; |
|||
414 | 160 | unset($params['#'], $params[$this->routeParam]); |
|||
415 | |||||
416 | 160 | $route = trim(isset($params[0]) ? $params[0] : '', '/'); |
|||
417 | 160 | unset($params[0]); |
|||
418 | |||||
419 | 160 | $baseUrl = $this->showScriptName || !$this->enablePrettyUrl ? $this->getScriptUrl() : $this->getBaseUrl(); |
|||
420 | |||||
421 | 160 | if ($this->enablePrettyUrl) { |
|||
422 | 82 | $cacheKey = $route . '?'; |
|||
423 | 82 | foreach ($params as $key => $value) { |
|||
424 | 81 | if ($value !== null) { |
|||
425 | 81 | $cacheKey .= $key . '&'; |
|||
426 | } |
||||
427 | } |
||||
428 | |||||
429 | 82 | $url = $this->getUrlFromCache($cacheKey, $route, $params); |
|||
430 | 82 | if ($url === false) { |
|||
431 | /** @var UrlRule $rule */ |
||||
432 | 82 | foreach ($this->rules as $rule) { |
|||
433 | 64 | if (in_array($rule, $this->_ruleCache[$cacheKey], true)) { |
|||
434 | // avoid redundant calls of `UrlRule::createUrl()` for rules checked in `getUrlFromCache()` |
||||
435 | // @see https://github.com/yiisoft/yii2/issues/14094 |
||||
436 | 21 | continue; |
|||
437 | } |
||||
438 | 64 | $url = $rule->createUrl($this, $route, $params); |
|||
439 | 64 | if ($this->canBeCached($rule)) { |
|||
440 | 64 | $this->setRuleToCache($cacheKey, $rule); |
|||
441 | } |
||||
442 | 64 | if ($url !== false) { |
|||
443 | 64 | break; |
|||
444 | } |
||||
445 | } |
||||
446 | } |
||||
447 | |||||
448 | 82 | if ($url !== false) { |
|||
449 | 64 | if (strpos($url, '://') !== false) { |
|||
450 | 8 | if ($baseUrl !== '' && ($pos = strpos($url, '/', 8)) !== false) { |
|||
451 | 3 | return substr($url, 0, $pos) . $baseUrl . substr($url, $pos) . $anchor; |
|||
452 | } |
||||
453 | |||||
454 | 5 | return $url . $baseUrl . $anchor; |
|||
455 | 56 | } elseif (strncmp($url, '//', 2) === 0) { |
|||
456 | 4 | if ($baseUrl !== '' && ($pos = strpos($url, '/', 2)) !== false) { |
|||
457 | 3 | return substr($url, 0, $pos) . $baseUrl . substr($url, $pos) . $anchor; |
|||
458 | } |
||||
459 | |||||
460 | 4 | return $url . $baseUrl . $anchor; |
|||
461 | } |
||||
462 | |||||
463 | 52 | $url = ltrim($url, '/'); |
|||
464 | 52 | return "$baseUrl/{$url}{$anchor}"; |
|||
465 | } |
||||
466 | |||||
467 | 66 | if ($this->suffix !== null) { |
|||
468 | 24 | $route .= $this->suffix; |
|||
469 | } |
||||
470 | 66 | if (!empty($params) && ($query = http_build_query($params)) !== '') { |
|||
471 | 49 | $route .= '?' . $query; |
|||
472 | } |
||||
473 | |||||
474 | 66 | $route = ltrim($route, '/'); |
|||
475 | 66 | return "$baseUrl/{$route}{$anchor}"; |
|||
476 | } |
||||
477 | |||||
478 | 78 | $url = "$baseUrl?{$this->routeParam}=" . urlencode($route); |
|||
479 | 78 | if (!empty($params) && ($query = http_build_query($params)) !== '') { |
|||
480 | 62 | $url .= '&' . $query; |
|||
481 | } |
||||
482 | |||||
483 | 78 | return $url . $anchor; |
|||
484 | } |
||||
485 | |||||
486 | /** |
||||
487 | * Returns the value indicating whether result of [[createUrl()]] of rule should be cached in internal cache. |
||||
488 | * |
||||
489 | * @param UrlRuleInterface $rule |
||||
490 | * @return bool `true` if result should be cached, `false` if not. |
||||
491 | * @since 2.0.12 |
||||
492 | * @see getUrlFromCache() |
||||
493 | * @see setRuleToCache() |
||||
494 | * @see UrlRule::getCreateUrlStatus() |
||||
495 | */ |
||||
496 | 64 | protected function canBeCached(UrlRuleInterface $rule) |
|||
497 | { |
||||
498 | 64 | return |
|||
499 | // if rule does not provide info about create status, we cache it every time to prevent bugs like #13350 |
||||
500 | // @see https://github.com/yiisoft/yii2/pull/13350#discussion_r114873476 |
||||
501 | 64 | !method_exists($rule, 'getCreateUrlStatus') || ($status = $rule->getCreateUrlStatus()) === null |
|||
502 | 64 | || $status === UrlRule::CREATE_STATUS_SUCCESS |
|||
503 | 64 | || $status & UrlRule::CREATE_STATUS_PARAMS_MISMATCH; |
|||
504 | } |
||||
505 | |||||
506 | /** |
||||
507 | * Get URL from internal cache if exists. |
||||
508 | * @param string $cacheKey generated cache key to store data. |
||||
509 | * @param string $route the route (e.g. `site/index`). |
||||
510 | * @param array $params rule params. |
||||
511 | * @return bool|string the created URL |
||||
512 | * @see createUrl() |
||||
513 | * @since 2.0.8 |
||||
514 | */ |
||||
515 | 82 | protected function getUrlFromCache($cacheKey, $route, $params) |
|||
516 | { |
||||
517 | 82 | if (!empty($this->_ruleCache[$cacheKey])) { |
|||
518 | 63 | foreach ($this->_ruleCache[$cacheKey] as $rule) { |
|||
519 | /** @var UrlRule $rule */ |
||||
520 | 63 | if (($url = $rule->createUrl($this, $route, $params)) !== false) { |
|||
521 | 63 | return $url; |
|||
522 | } |
||||
523 | } |
||||
524 | } else { |
||||
525 | 82 | $this->_ruleCache[$cacheKey] = []; |
|||
526 | } |
||||
527 | |||||
528 | 82 | return false; |
|||
529 | } |
||||
530 | |||||
531 | /** |
||||
532 | * Store rule (e.g. [[UrlRule]]) to internal cache. |
||||
533 | * @param $cacheKey |
||||
534 | * @param UrlRuleInterface $rule |
||||
535 | * @since 2.0.8 |
||||
536 | */ |
||||
537 | 64 | protected function setRuleToCache($cacheKey, UrlRuleInterface $rule) |
|||
538 | { |
||||
539 | 64 | $this->_ruleCache[$cacheKey][] = $rule; |
|||
540 | } |
||||
541 | |||||
542 | /** |
||||
543 | * Creates an absolute URL using the given route and query parameters. |
||||
544 | * |
||||
545 | * This method prepends the URL created by [[createUrl()]] with the [[hostInfo]]. |
||||
546 | * |
||||
547 | * Note that unlike [[\yii\helpers\Url::toRoute()]], this method always treats the given route |
||||
548 | * as an absolute route. |
||||
549 | * |
||||
550 | * @param string|array $params use a string to represent a route (e.g. `site/index`), |
||||
551 | * or an array to represent a route with query parameters (e.g. `['site/index', 'param1' => 'value1']`). |
||||
552 | * @param string|null $scheme the scheme to use for the URL (either `http`, `https` or empty string |
||||
553 | * for protocol-relative URL). |
||||
554 | * If not specified the scheme of the current request will be used. |
||||
555 | * @return string the created URL |
||||
556 | * @see createUrl() |
||||
557 | */ |
||||
558 | 60 | public function createAbsoluteUrl($params, $scheme = null) |
|||
559 | { |
||||
560 | 60 | $params = (array) $params; |
|||
561 | 60 | $url = $this->createUrl($params); |
|||
562 | 60 | if (strpos($url, '://') === false) { |
|||
563 | 56 | $hostInfo = $this->getHostInfo(); |
|||
564 | 56 | if (strncmp($url, '//', 2) === 0) { |
|||
565 | 4 | $url = substr($hostInfo, 0, strpos($hostInfo, '://')) . ':' . $url; |
|||
566 | } else { |
||||
567 | 56 | $url = $hostInfo . $url; |
|||
568 | } |
||||
569 | } |
||||
570 | |||||
571 | 60 | return Url::ensureScheme($url, $scheme); |
|||
572 | } |
||||
573 | |||||
574 | /** |
||||
575 | * Returns the base URL that is used by [[createUrl()]] to prepend to created URLs. |
||||
576 | * It defaults to [[Request::baseUrl]]. |
||||
577 | * This is mainly used when [[enablePrettyUrl]] is `true` and [[showScriptName]] is `false`. |
||||
578 | * @return string the base URL that is used by [[createUrl()]] to prepend to created URLs. |
||||
579 | * @throws InvalidConfigException if running in console application and [[baseUrl]] is not configured. |
||||
580 | */ |
||||
581 | 44 | public function getBaseUrl() |
|||
582 | { |
||||
583 | 44 | if ($this->_baseUrl === null) { |
|||
584 | 3 | $request = Yii::$app->getRequest(); |
|||
585 | 3 | if ($request instanceof Request) { |
|||
586 | 3 | $this->_baseUrl = $request->getBaseUrl(); |
|||
587 | } else { |
||||
588 | throw new InvalidConfigException('Please configure UrlManager::baseUrl correctly as you are running a console application.'); |
||||
589 | } |
||||
590 | } |
||||
591 | |||||
592 | 44 | return $this->_baseUrl; |
|||
593 | } |
||||
594 | |||||
595 | /** |
||||
596 | * Sets the base URL that is used by [[createUrl()]] to prepend to created URLs. |
||||
597 | * This is mainly used when [[enablePrettyUrl]] is `true` and [[showScriptName]] is `false`. |
||||
598 | * @param string $value the base URL that is used by [[createUrl()]] to prepend to created URLs. |
||||
599 | */ |
||||
600 | 126 | public function setBaseUrl($value) |
|||
601 | { |
||||
602 | 126 | $this->_baseUrl = $value === null ? null : rtrim(Yii::getAlias($value), '/'); |
|||
0 ignored issues
–
show
It seems like
Yii::getAlias($value) can also be of type false ; however, parameter $string of rtrim() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
603 | } |
||||
604 | |||||
605 | /** |
||||
606 | * Returns the entry script URL that is used by [[createUrl()]] to prepend to created URLs. |
||||
607 | * It defaults to [[Request::scriptUrl]]. |
||||
608 | * This is mainly used when [[enablePrettyUrl]] is `false` or [[showScriptName]] is `true`. |
||||
609 | * @return string the entry script URL that is used by [[createUrl()]] to prepend to created URLs. |
||||
610 | * @throws InvalidConfigException if running in console application and [[scriptUrl]] is not configured. |
||||
611 | */ |
||||
612 | 118 | public function getScriptUrl() |
|||
613 | { |
||||
614 | 118 | if ($this->_scriptUrl === null) { |
|||
615 | 18 | $request = Yii::$app->getRequest(); |
|||
616 | 18 | if ($request instanceof Request) { |
|||
617 | 18 | $this->_scriptUrl = $request->getScriptUrl(); |
|||
618 | } else { |
||||
619 | throw new InvalidConfigException('Please configure UrlManager::scriptUrl correctly as you are running a console application.'); |
||||
620 | } |
||||
621 | } |
||||
622 | |||||
623 | 118 | return $this->_scriptUrl; |
|||
624 | } |
||||
625 | |||||
626 | /** |
||||
627 | * Sets the entry script URL that is used by [[createUrl()]] to prepend to created URLs. |
||||
628 | * This is mainly used when [[enablePrettyUrl]] is `false` or [[showScriptName]] is `true`. |
||||
629 | * @param string $value the entry script URL that is used by [[createUrl()]] to prepend to created URLs. |
||||
630 | */ |
||||
631 | 148 | public function setScriptUrl($value) |
|||
632 | { |
||||
633 | 148 | $this->_scriptUrl = $value; |
|||
634 | } |
||||
635 | |||||
636 | /** |
||||
637 | * Returns the host info that is used by [[createAbsoluteUrl()]] to prepend to created URLs. |
||||
638 | * @return string the host info (e.g. `https://www.example.com`) that is used by [[createAbsoluteUrl()]] to prepend to created URLs. |
||||
639 | * @throws InvalidConfigException if running in console application and [[hostInfo]] is not configured. |
||||
640 | */ |
||||
641 | 58 | public function getHostInfo() |
|||
642 | { |
||||
643 | 58 | if ($this->_hostInfo === null) { |
|||
644 | 9 | $request = Yii::$app->getRequest(); |
|||
645 | 9 | if ($request instanceof \yii\web\Request) { |
|||
646 | 9 | $this->_hostInfo = $request->getHostInfo(); |
|||
647 | } else { |
||||
648 | throw new InvalidConfigException('Please configure UrlManager::hostInfo correctly as you are running a console application.'); |
||||
649 | } |
||||
650 | } |
||||
651 | |||||
652 | 58 | return $this->_hostInfo; |
|||
653 | } |
||||
654 | |||||
655 | /** |
||||
656 | * Sets the host info that is used by [[createAbsoluteUrl()]] to prepend to created URLs. |
||||
657 | * @param string $value the host info (e.g. "https://www.example.com") that is used by [[createAbsoluteUrl()]] to prepend to created URLs. |
||||
658 | */ |
||||
659 | 111 | public function setHostInfo($value) |
|||
660 | { |
||||
661 | 111 | $this->_hostInfo = $value === null ? null : rtrim($value, '/'); |
|||
0 ignored issues
–
show
|
|||||
662 | } |
||||
663 | } |
||||
664 |