PageRenderTime 47ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/vendor/laravel/framework/src/Illuminate/Routing/UrlGenerator.php

https://gitlab.com/kimting254/wbms
PHP | 711 lines | 308 code | 87 blank | 316 comment | 16 complexity | 9472b63e3fe15bca8899286f3d8c18db MD5 | raw file
  1. <?php namespace Illuminate\Routing;
  2. use Illuminate\Http\Request;
  3. use InvalidArgumentException;
  4. use Illuminate\Contracts\Routing\UrlRoutable;
  5. use Illuminate\Contracts\Routing\UrlGenerator as UrlGeneratorContract;
  6. class UrlGenerator implements UrlGeneratorContract {
  7. /**
  8. * The route collection.
  9. *
  10. * @var \Illuminate\Routing\RouteCollection
  11. */
  12. protected $routes;
  13. /**
  14. * The request instance.
  15. *
  16. * @var \Illuminate\Http\Request
  17. */
  18. protected $request;
  19. /**
  20. * The forced URL root.
  21. *
  22. * @var string
  23. */
  24. protected $forcedRoot;
  25. /**
  26. * The forced schema for URLs.
  27. *
  28. * @var string
  29. */
  30. protected $forceSchema;
  31. /**
  32. * A cached copy of the URL root for the current request.
  33. *
  34. * @var string|null
  35. */
  36. protected $cachedRoot;
  37. /**
  38. * A cached copy of the URL schema for the current request.
  39. *
  40. * @var string|null
  41. */
  42. protected $cachedSchema;
  43. /**
  44. * The root namespace being applied to controller actions.
  45. *
  46. * @var string
  47. */
  48. protected $rootNamespace;
  49. /**
  50. * The session resolver callable.
  51. *
  52. * @var callable
  53. */
  54. protected $sessionResolver;
  55. /**
  56. * Characters that should not be URL encoded.
  57. *
  58. * @var array
  59. */
  60. protected $dontEncode = array(
  61. '%2F' => '/',
  62. '%40' => '@',
  63. '%3A' => ':',
  64. '%3B' => ';',
  65. '%2C' => ',',
  66. '%3D' => '=',
  67. '%2B' => '+',
  68. '%21' => '!',
  69. '%2A' => '*',
  70. '%7C' => '|',
  71. '%3F' => '?',
  72. '%26' => '&',
  73. '%23' => '#',
  74. '%25' => '%',
  75. );
  76. /**
  77. * Create a new URL Generator instance.
  78. *
  79. * @param \Illuminate\Routing\RouteCollection $routes
  80. * @param \Illuminate\Http\Request $request
  81. * @return void
  82. */
  83. public function __construct(RouteCollection $routes, Request $request)
  84. {
  85. $this->routes = $routes;
  86. $this->setRequest($request);
  87. }
  88. /**
  89. * Get the full URL for the current request.
  90. *
  91. * @return string
  92. */
  93. public function full()
  94. {
  95. return $this->request->fullUrl();
  96. }
  97. /**
  98. * Get the current URL for the request.
  99. *
  100. * @return string
  101. */
  102. public function current()
  103. {
  104. return $this->to($this->request->getPathInfo());
  105. }
  106. /**
  107. * Get the URL for the previous request.
  108. *
  109. * @return string
  110. */
  111. public function previous()
  112. {
  113. $referrer = $this->request->headers->get('referer');
  114. $url = $referrer ? $this->to($referrer) : $this->getPreviousUrlFromSession();
  115. return $url ?: $this->to('/');
  116. }
  117. /**
  118. * Generate a absolute URL to the given path.
  119. *
  120. * @param string $path
  121. * @param mixed $extra
  122. * @param bool|null $secure
  123. * @return string
  124. */
  125. public function to($path, $extra = array(), $secure = null)
  126. {
  127. // First we will check if the URL is already a valid URL. If it is we will not
  128. // try to generate a new one but will simply return the URL as is, which is
  129. // convenient since developers do not always have to check if it's valid.
  130. if ($this->isValidUrl($path)) return $path;
  131. $scheme = $this->getScheme($secure);
  132. $extra = $this->formatParameters($extra);
  133. $tail = implode('/', array_map(
  134. 'rawurlencode', (array) $extra)
  135. );
  136. // Once we have the scheme we will compile the "tail" by collapsing the values
  137. // into a single string delimited by slashes. This just makes it convenient
  138. // for passing the array of parameters to this URL as a list of segments.
  139. $root = $this->getRootUrl($scheme);
  140. return $this->trimUrl($root, $path, $tail);
  141. }
  142. /**
  143. * Generate a secure, absolute URL to the given path.
  144. *
  145. * @param string $path
  146. * @param array $parameters
  147. * @return string
  148. */
  149. public function secure($path, $parameters = array())
  150. {
  151. return $this->to($path, $parameters, true);
  152. }
  153. /**
  154. * Generate a URL to an application asset.
  155. *
  156. * @param string $path
  157. * @param bool|null $secure
  158. * @return string
  159. */
  160. public function asset($path, $secure = null)
  161. {
  162. if ($this->isValidUrl($path)) return $path;
  163. // Once we get the root URL, we will check to see if it contains an index.php
  164. // file in the paths. If it does, we will remove it since it is not needed
  165. // for asset paths, but only for routes to endpoints in the application.
  166. $root = $this->getRootUrl($this->getScheme($secure));
  167. return $this->removeIndex($root).'/'.trim($path, '/');
  168. }
  169. /**
  170. * Remove the index.php file from a path.
  171. *
  172. * @param string $root
  173. * @return string
  174. */
  175. protected function removeIndex($root)
  176. {
  177. $i = 'index.php';
  178. return str_contains($root, $i) ? str_replace('/'.$i, '', $root) : $root;
  179. }
  180. /**
  181. * Generate a URL to a secure asset.
  182. *
  183. * @param string $path
  184. * @return string
  185. */
  186. public function secureAsset($path)
  187. {
  188. return $this->asset($path, true);
  189. }
  190. /**
  191. * Get the scheme for a raw URL.
  192. *
  193. * @param bool|null $secure
  194. * @return string
  195. */
  196. protected function getScheme($secure)
  197. {
  198. if (is_null($secure))
  199. {
  200. if (is_null($this->cachedSchema))
  201. {
  202. $this->cachedSchema = $this->forceSchema ?: $this->request->getScheme().'://';
  203. }
  204. return $this->cachedSchema;
  205. }
  206. return $secure ? 'https://' : 'http://';
  207. }
  208. /**
  209. * Force the schema for URLs.
  210. *
  211. * @param string $schema
  212. * @return void
  213. */
  214. public function forceSchema($schema)
  215. {
  216. $this->cachedSchema = null;
  217. $this->forceSchema = $schema.'://';
  218. }
  219. /**
  220. * Get the URL to a named route.
  221. *
  222. * @param string $name
  223. * @param mixed $parameters
  224. * @param bool $absolute
  225. * @return string
  226. *
  227. * @throws \InvalidArgumentException
  228. */
  229. public function route($name, $parameters = array(), $absolute = true)
  230. {
  231. if ( ! is_null($route = $this->routes->getByName($name)))
  232. {
  233. return $this->toRoute($route, $parameters, $absolute);
  234. }
  235. throw new InvalidArgumentException("Route [{$name}] not defined.");
  236. }
  237. /**
  238. * Get the URL for a given route instance.
  239. *
  240. * @param \Illuminate\Routing\Route $route
  241. * @param mixed $parameters
  242. * @param bool $absolute
  243. * @return string
  244. */
  245. protected function toRoute($route, $parameters, $absolute)
  246. {
  247. $parameters = $this->formatParameters($parameters);
  248. $domain = $this->getRouteDomain($route, $parameters);
  249. $uri = strtr(rawurlencode($this->addQueryString($this->trimUrl(
  250. $root = $this->replaceRoot($route, $domain, $parameters),
  251. $this->replaceRouteParameters($route->uri(), $parameters)
  252. ), $parameters)), $this->dontEncode);
  253. return $absolute ? $uri : '/'.ltrim(str_replace($root, '', $uri), '/');
  254. }
  255. /**
  256. * Replace the parameters on the root path.
  257. *
  258. * @param \Illuminate\Routing\Route $route
  259. * @param string $domain
  260. * @param array $parameters
  261. * @return string
  262. */
  263. protected function replaceRoot($route, $domain, &$parameters)
  264. {
  265. return $this->replaceRouteParameters($this->getRouteRoot($route, $domain), $parameters);
  266. }
  267. /**
  268. * Replace all of the wildcard parameters for a route path.
  269. *
  270. * @param string $path
  271. * @param array $parameters
  272. * @return string
  273. */
  274. protected function replaceRouteParameters($path, array &$parameters)
  275. {
  276. if (count($parameters))
  277. {
  278. $path = preg_replace_sub(
  279. '/\{.*?\}/', $parameters, $this->replaceNamedParameters($path, $parameters)
  280. );
  281. }
  282. return trim(preg_replace('/\{.*?\?\}/', '', $path), '/');
  283. }
  284. /**
  285. * Replace all of the named parameters in the path.
  286. *
  287. * @param string $path
  288. * @param array $parameters
  289. * @return string
  290. */
  291. protected function replaceNamedParameters($path, &$parameters)
  292. {
  293. return preg_replace_callback('/\{(.*?)\??\}/', function($m) use (&$parameters)
  294. {
  295. return isset($parameters[$m[1]]) ? array_pull($parameters, $m[1]) : $m[0];
  296. }, $path);
  297. }
  298. /**
  299. * Add a query string to the URI.
  300. *
  301. * @param string $uri
  302. * @param array $parameters
  303. * @return mixed|string
  304. */
  305. protected function addQueryString($uri, array $parameters)
  306. {
  307. // If the URI has a fragment, we will move it to the end of the URI since it will
  308. // need to come after any query string that may be added to the URL else it is
  309. // not going to be available. We will remove it then append it back on here.
  310. if ( ! is_null($fragment = parse_url($uri, PHP_URL_FRAGMENT)))
  311. {
  312. $uri = preg_replace('/#.*/', '', $uri);
  313. }
  314. $uri .= $this->getRouteQueryString($parameters);
  315. return is_null($fragment) ? $uri : $uri."#{$fragment}";
  316. }
  317. /**
  318. * Format the array of URL parameters.
  319. *
  320. * @param mixed|array $parameters
  321. * @return array
  322. */
  323. protected function formatParameters($parameters)
  324. {
  325. return $this->replaceRoutableParameters($parameters);
  326. }
  327. /**
  328. * Replace UrlRoutable parameters with their route parameter.
  329. *
  330. * @param array $parameters
  331. * @return array
  332. */
  333. protected function replaceRoutableParameters($parameters = array())
  334. {
  335. $parameters = is_array($parameters) ? $parameters : array($parameters);
  336. foreach ($parameters as $key => $parameter)
  337. {
  338. if ($parameter instanceof UrlRoutable)
  339. {
  340. $parameters[$key] = $parameter->getRouteKey();
  341. }
  342. }
  343. return $parameters;
  344. }
  345. /**
  346. * Get the query string for a given route.
  347. *
  348. * @param array $parameters
  349. * @return string
  350. */
  351. protected function getRouteQueryString(array $parameters)
  352. {
  353. // First we will get all of the string parameters that are remaining after we
  354. // have replaced the route wildcards. We'll then build a query string from
  355. // these string parameters then use it as a starting point for the rest.
  356. if (count($parameters) == 0) return '';
  357. $query = http_build_query(
  358. $keyed = $this->getStringParameters($parameters)
  359. );
  360. // Lastly, if there are still parameters remaining, we will fetch the numeric
  361. // parameters that are in the array and add them to the query string or we
  362. // will make the initial query string if it wasn't started with strings.
  363. if (count($keyed) < count($parameters))
  364. {
  365. $query .= '&'.implode(
  366. '&', $this->getNumericParameters($parameters)
  367. );
  368. }
  369. return '?'.trim($query, '&');
  370. }
  371. /**
  372. * Get the string parameters from a given list.
  373. *
  374. * @param array $parameters
  375. * @return array
  376. */
  377. protected function getStringParameters(array $parameters)
  378. {
  379. return array_where($parameters, function($k, $v) { return is_string($k); });
  380. }
  381. /**
  382. * Get the numeric parameters from a given list.
  383. *
  384. * @param array $parameters
  385. * @return array
  386. */
  387. protected function getNumericParameters(array $parameters)
  388. {
  389. return array_where($parameters, function($k, $v) { return is_numeric($k); });
  390. }
  391. /**
  392. * Get the formatted domain for a given route.
  393. *
  394. * @param \Illuminate\Routing\Route $route
  395. * @param array $parameters
  396. * @return string
  397. */
  398. protected function getRouteDomain($route, &$parameters)
  399. {
  400. return $route->domain() ? $this->formatDomain($route, $parameters) : null;
  401. }
  402. /**
  403. * Format the domain and port for the route and request.
  404. *
  405. * @param \Illuminate\Routing\Route $route
  406. * @param array $parameters
  407. * @return string
  408. */
  409. protected function formatDomain($route, &$parameters)
  410. {
  411. return $this->addPortToDomain($this->getDomainAndScheme($route));
  412. }
  413. /**
  414. * Get the domain and scheme for the route.
  415. *
  416. * @param \Illuminate\Routing\Route $route
  417. * @return string
  418. */
  419. protected function getDomainAndScheme($route)
  420. {
  421. return $this->getRouteScheme($route).$route->domain();
  422. }
  423. /**
  424. * Add the port to the domain if necessary.
  425. *
  426. * @param string $domain
  427. * @return string
  428. */
  429. protected function addPortToDomain($domain)
  430. {
  431. if (in_array($this->request->getPort(), array('80', '443')))
  432. {
  433. return $domain;
  434. }
  435. return $domain.':'.$this->request->getPort();
  436. }
  437. /**
  438. * Get the root of the route URL.
  439. *
  440. * @param \Illuminate\Routing\Route $route
  441. * @param string $domain
  442. * @return string
  443. */
  444. protected function getRouteRoot($route, $domain)
  445. {
  446. return $this->getRootUrl($this->getRouteScheme($route), $domain);
  447. }
  448. /**
  449. * Get the scheme for the given route.
  450. *
  451. * @param \Illuminate\Routing\Route $route
  452. * @return string
  453. */
  454. protected function getRouteScheme($route)
  455. {
  456. if ($route->httpOnly())
  457. {
  458. return $this->getScheme(false);
  459. }
  460. elseif ($route->httpsOnly())
  461. {
  462. return $this->getScheme(true);
  463. }
  464. return $this->getScheme(null);
  465. }
  466. /**
  467. * Get the URL to a controller action.
  468. *
  469. * @param string $action
  470. * @param mixed $parameters
  471. * @param bool $absolute
  472. * @return string
  473. *
  474. * @throws \InvalidArgumentException
  475. */
  476. public function action($action, $parameters = array(), $absolute = true)
  477. {
  478. if ($this->rootNamespace && ! (strpos($action, '\\') === 0))
  479. {
  480. $action = $this->rootNamespace.'\\'.$action;
  481. }
  482. else
  483. {
  484. $action = trim($action, '\\');
  485. }
  486. if ( ! is_null($route = $this->routes->getByAction($action)))
  487. {
  488. return $this->toRoute($route, $parameters, $absolute);
  489. }
  490. throw new InvalidArgumentException("Action {$action} not defined.");
  491. }
  492. /**
  493. * Get the base URL for the request.
  494. *
  495. * @param string $scheme
  496. * @param string $root
  497. * @return string
  498. */
  499. protected function getRootUrl($scheme, $root = null)
  500. {
  501. if (is_null($root))
  502. {
  503. if (is_null($this->cachedRoot))
  504. {
  505. $this->cachedRoot = $this->forcedRoot ?: $this->request->root();
  506. }
  507. $root = $this->cachedRoot;
  508. }
  509. $start = starts_with($root, 'http://') ? 'http://' : 'https://';
  510. return preg_replace('~'.$start.'~', $scheme, $root, 1);
  511. }
  512. /**
  513. * Set the forced root URL.
  514. *
  515. * @param string $root
  516. * @return void
  517. */
  518. public function forceRootUrl($root)
  519. {
  520. $this->forcedRoot = rtrim($root, '/');
  521. $this->cachedRoot = null;
  522. }
  523. /**
  524. * Determine if the given path is a valid URL.
  525. *
  526. * @param string $path
  527. * @return bool
  528. */
  529. public function isValidUrl($path)
  530. {
  531. if (starts_with($path, ['#', '//', 'mailto:', 'tel:', 'http://', 'https://'])) return true;
  532. return filter_var($path, FILTER_VALIDATE_URL) !== false;
  533. }
  534. /**
  535. * Format the given URL segments into a single URL.
  536. *
  537. * @param string $root
  538. * @param string $path
  539. * @param string $tail
  540. * @return string
  541. */
  542. protected function trimUrl($root, $path, $tail = '')
  543. {
  544. return trim($root.'/'.trim($path.'/'.$tail, '/'), '/');
  545. }
  546. /**
  547. * Get the request instance.
  548. *
  549. * @return \Symfony\Component\HttpFoundation\Request
  550. */
  551. public function getRequest()
  552. {
  553. return $this->request;
  554. }
  555. /**
  556. * Set the current request instance.
  557. *
  558. * @param \Illuminate\Http\Request $request
  559. * @return void
  560. */
  561. public function setRequest(Request $request)
  562. {
  563. $this->request = $request;
  564. $this->cachedRoot = null;
  565. $this->cachedSchema = null;
  566. }
  567. /**
  568. * Set the route collection.
  569. *
  570. * @param \Illuminate\Routing\RouteCollection $routes
  571. * @return $this
  572. */
  573. public function setRoutes(RouteCollection $routes)
  574. {
  575. $this->routes = $routes;
  576. return $this;
  577. }
  578. /**
  579. * Get the previous URL from the session if possible.
  580. *
  581. * @return string|null
  582. */
  583. protected function getPreviousUrlFromSession()
  584. {
  585. $session = $this->getSession();
  586. return $session ? $session->previousUrl() : null;
  587. }
  588. /**
  589. * Get the session implementation from the resolver.
  590. *
  591. * @return \Illuminate\Session\Store
  592. */
  593. protected function getSession()
  594. {
  595. return call_user_func($this->sessionResolver ?: function() {});
  596. }
  597. /**
  598. * Set the session resolver for the generator.
  599. *
  600. * @param callable $sessionResolver
  601. * @return $this
  602. */
  603. public function setSessionResolver(callable $sessionResolver)
  604. {
  605. $this->sessionResolver = $sessionResolver;
  606. return $this;
  607. }
  608. /**
  609. * Set the root controller namespace.
  610. *
  611. * @param string $rootNamespace
  612. * @return $this
  613. */
  614. public function setRootControllerNamespace($rootNamespace)
  615. {
  616. $this->rootNamespace = $rootNamespace;
  617. return $this;
  618. }
  619. }